Git Product home page Git Product logo

Comments (21)

xicilion avatar xicilion commented on June 26, 2024 1

0c184d1
supported.

from fibjs.

xicilion avatar xicilion commented on June 26, 2024 1

In SNICallback, I can change/add/remove SecureContexts seamlessly. Am I right?

yes.

If SNI is disabled in the web browsers, how will the server send the right certificate?

the server just send the default certificate. Cloudflare works in that manner.

I think that SNICallback can be optimized by WASM in the future without making FibJS complex.

Actually, the problem does not lie with JavaScript, but rather with the environmental switch.

Can we have these two solutions (template and SNICallback) together?

SNICallback is eaier, I just dont like it.

I will think it over.

from fibjs.

xicilion avatar xicilion commented on June 26, 2024 1

Cool, there are so many ideas. Let us sum up:

  • we need a js callback function, so that we can catch missing certificates and resolve it.
    • function name may be getSecureContext/secureContextResolver, it is better than SNICallback.
    • the callback function does not need to be compatible with SNICallback, it can be a synchronous function, which will make it less likely to go wrong.
  • we need to cache the certificatest to avoid calling the js function every time.
    • we can cache the certificatest using the CN name and SAN list.
  • we need to automatically clean the cache to avoid storing too many certificates in it.
    • We can use the LRU algorithm to manage the cache, where we can set update timeouts and cache sizes. Certificates that exceed the timeout will be cleared, and when the size is exceeded, the least recently used certificates will also be cleared.
  • We need a manual cleaning method that can actively clear the cache.
    • it may be clearSecureContexts/removeSecureContext(name)

from fibjs.

xicilion avatar xicilion commented on June 26, 2024 1

It's almost done. it looks like this:

it('set/get', () => {
    var ctx = tls.createSecureContext(true);
    ctx.setSNIContext("test", sni_resolver("test"));
    ctx.setSNIContext("test1", sni_resolver("test1"));

    assert.equal(ctx.getSNIContext("test").cert.subject, 'CN=test');
    assert.equal(ctx.getSNIContext("test1").cert.subject, 'CN=test1');
});

it('resolver', () => {
    var ctx = tls.createSecureContext({
        "SNIResolver": sni_resolver
    }, true);

    assert.equal(ctx.getSNIContext("test", true).cert.subject, 'CN=test');
    assert.equal(ctx.getSNIContext("test1", true).cert.subject, 'CN=test1');
});

it('delete', () => {
    var ctx = tls.createSecureContext(true);
    ctx.setSNIContext("test", sni_resolver("test"));
    ctx.setSNIContext("test1", sni_resolver("test1"));

    ctx.removeSNIContext("test");

    assert.equal(ctx.getSNIContext("test"), undefined);
    assert.equal(ctx.getSNIContext("test1").cert.subject, 'CN=test1');
});

it('size', () => {
    var ctx = tls.createSecureContext({
        "SNICacheSize": 2
    }, true);
    ctx.setSNIContext("test", sni_resolver("test"));
    ctx.setSNIContext("test1", sni_resolver("test1"));
    ctx.setSNIContext("test2", sni_resolver("test2"));

    assert.equal(ctx.getSNIContext("test"), undefined);
    assert.equal(ctx.getSNIContext("test1").cert.subject, 'CN=test1');
    assert.equal(ctx.getSNIContext("test2").cert.subject, 'CN=test2');
});

it('timeout', () => {
    var ctx = tls.createSecureContext({
        "SNICacheTimeout": 200
    }, true);
    ctx.setSNIContext("test", sni_resolver("test"));

    coroutine.sleep(400);
    assert.equal(ctx.getSNIContext("test"), undefined);
});

done.
2d9024d

from fibjs.

xicilion avatar xicilion commented on June 26, 2024

The current version of FibJS supports SNI certificates, but this feature is not designed for updating certificates. However, the development branch of FibJS is currently upgrading the SSL library to OpenSSL, and SNI is considered an insecure protocol. Therefore, SNI support will not be included in the version of FibJS after upgrading to OpenSSL.

Given that your requirement is to update certificates, I recommend restarting the server. Updating certificates is not a frequent operation, and introducing a callback during SSL handshake for this purpose may not be very worthwhile.

from fibjs.

xicilion avatar xicilion commented on June 26, 2024

I checked the documentation of node.js and found that it supports setSecureContext:
https://nodejs.org/docs/latest/api/tls.html#serversetsecurecontextoptions
This seems like a better way to change certificates.

from fibjs.

nezarati avatar nezarati commented on June 26, 2024

Given that your requirement is to update certificates, I recommend restarting the server. Updating certificates is not a frequent operation, and introducing a callback during SSL handshake for this purpose may not be very worthwhile.

Imagine an object-based storage service with user-defined domains. The getCertificate feature allows adding or removing user certificates without restarting the server. Therefore, in multi-tenant applications with a lot of custom domains, this feature is useful.

NGINX supports this feature using njs and Lua:

As a radical idea, I plan to use FibJS instead of NGINX as a reverse proxy in a CDN in the future.

from fibjs.

xicilion avatar xicilion commented on June 26, 2024

what about setSecureContext, it can also be used to set cert/key without restarting the server.

from fibjs.

nezarati avatar nezarati commented on June 26, 2024

Yes, But it is good for only one SecureContext.

Suppose that I have 10,000 secure contexts and each secureContext.cert (a single SSL certificate) may have additional host names (Subject Alternative Name) and wildcards.

let contexts: Array<SecureContext> = [];
for (let row of db.select('domain_certificates')) {
    contexts.push(createSecureContextFrom(row));
}

server.setSecureContext(contexts); // it is wrong.

setSecureContext accepts only a single secureContext.
I think that we need a separate function like getCertificate instead of setSecureContext. because:

  • How to pass multiple secure contexts to setSecureContext?
  • What algorithm is used to find a match by setSecureContext? Linear search or better algorithms?
  • How does setSecureContext support SAN and wildcards?

If we have a user-defined function getCertificate, it can handle the mentioned problems.
Its input is domain name and its output is the corresponding SecureContext.

from fibjs.

xicilion avatar xicilion commented on June 26, 2024

So the point is that you need SNI support insteed of changing cert.

We need to consider a few issues:

  • there are security concerns related to SNI technology itself, and Chrome browser has already provided an option to disable it. However, many services are still using SNI, so it may not be a problem for now.
  • I still don't like switching to JavaScript to query certificates every handshake, as it may affect performance. This is something to consider in high-performance scenarios.

As a solution, I'm considering whether we can achieve this by extending setSecureContext, for example, adding a domain template parameter to setSecureContext to modify the certificate of the specified domain.

This way, SSL handshake can be done without switching to the JS environment. If required by the business, we can modify the certificate of the specified domain template at any time.

from fibjs.

xicilion avatar xicilion commented on June 26, 2024
  • What algorithm is used to find a match by setSecureContext? Linear search or better algorithms?

good point. we should consider the lookup algorithms when there ars lots of certificates that need to be matched.

We can use an optimized template algorithm to solve the scaling problem. For example, if the domain name is not a template, we use map to look it up, if it's not found in the map, then we use template traversal.

from fibjs.

xicilion avatar xicilion commented on June 26, 2024

and by using map, we can optimize template queries by continuously removing subdomains of the domain name and searching in different maps.

from fibjs.

nezarati avatar nezarati commented on June 26, 2024

In SNICallback, I can change/add/remove SecureContexts seamlessly. Am I right?

If SNI is disabled in the web browsers, how will the server send the right certificate?
Also, I don't know how the new TLS is implemented without SNI in low-level code.

I still don't like switching to JavaScript to query certificates every handshake
Yes, you are right. But this overhead is only for users who have configured SNICallback and for other users, the TLS handshake will be done without switching to the JS environment.

I think that SNICallback can be optimized by WASM in the future without making FibJS complex.

Can we have these two solutions (template and SNICallback) together?

from fibjs.

nezarati avatar nezarati commented on June 26, 2024

Actually, the problem does not lie with JavaScript, but rather with the environmental switch.

Is it possible to define a function for your solution in CPP that does not have the environmental switch cost, but I can override it in JS? Or am I thinking wrong?

Thank you for your time.

from fibjs.

xicilion avatar xicilion commented on June 26, 2024

plan A:

We can first lookup the certificate for domain in cache, If it cannot be found, then call SNICallback to resolve it.

plan B:

We can use SNICallback as a one-time function call for each domain.
After the SNICallback is called with a specific domain, fibjs will save the certificate with the domain in the cache.
If a user wants to change the certificate for a specific domain, they can do so using setSecureContext.

=============

maybe plan A is better. It is easier to implement and the results of the code are easier to understand.

from fibjs.

nezarati avatar nezarati commented on June 26, 2024

I think getSecureContext/secureContextResolver is a better name than SNICallback.

Plan A is good. But, how can users manage the cache?

Imagine that we have 10,000 SecureContexts.

  • Most of them are rarely-used and should not be in the cache.
  • Over time, some of them become useless and must be removed.
  • The cache needs a limit to store only frequently-used SecureContexts.

In the long run, the cache will be polluted and should be cleared.
Users need an API for cache management to prevent FibJS from leaking memory for unused SecureContexts.

FibJS uses getSecureContext to implicitly add a new SecureContext to the cache. The following solutions can be used to change/remove SecureContext:

Solution A
It is good if each SecureContext has a timeToCache. But, SecureContext may share between multiple domains and FibJS must periodically remove expired SecureContexts from cache.

Solution B
Make SecureContext.key and SecureContext.cert readwrite instead of readonly. So, users can implicitly change a SecureContext without manipulating the cache.
Users use clearSecureContexts/removeSecureContext(name) to explicitly remove unused SecureContexts from the cache.

Solution C
Is it possible for FibJS to use JSMap for caching and expose it to users?

from fibjs.

nezarati avatar nezarati commented on June 26, 2024

What is the difference between plan A and plan B?

  • In plan B for each domain, SNICallback is called only one time and FibJS caches its result forever.
  • Plan A is like plan B but the cache will periodically be cleared.
  • Or in plan A, FibJS will not cache the result of SNICallback.
  • Or something else?

from fibjs.

nezarati avatar nezarati commented on June 26, 2024

we can cache the certificatest using the CN name and SAN list.

Let's look at some examples of edge cases:

  • An end-user may make a certificate using multiple domains, but want to use one of them in our service. so the cache will be polluted.
  • An end-user may make multiple certificates over time and want to use the latest SAN list and some domains from the first SAN list.
  • Also the cache lookup algorithm must check wildcards.

So I think it is better to cache each SecureContext with the same name that FibJS passes to getSecureContext without using the CN name and SAN list.

from fibjs.

xicilion avatar xicilion commented on June 26, 2024

sure, make sense.

from fibjs.

nezarati avatar nezarati commented on June 26, 2024

I created another issue (#779) to prevent this issue from being off topic.
Can Torque prevent/reduce the environmental switch cost to use getSecureContext without caching?

from fibjs.

nezarati avatar nezarati commented on June 26, 2024

Everything looks very good 👌
Thanks a lot @xicilion.

from fibjs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.