But there is one way or there are multiple ways, again, to mitigate for a scenario, as it is outlined here, where you say, oh, now instead of getting the purple micro frontend or original purple one, we get this modified JavaScript code. So, the two ways to do it, and I'd like to talk more about the latter here, is to have code signing, which means you use an approach that's very similar to a JWT. You, let's say, have a public and a private key, and through the private key, you can, let's say, together with, for instance, the hash, put something in your code that says, well, if this is fulfilled, the code is properly signed, so you can read it out later, the code itself is still totally readable, and together with the public key, you verify that this hasn't been tampered with. But there's also a simpler way, so, of course, that makes some assumptions as well, and that is just to transport the integrity of the JavaScript file, and this is essentially just the hash function used on the binary contents of the file. Now, if we get, for instance, together with the reference that we usually have to a microphone, this integrity, so the hash, then we can, of course, use it to also verify that the content hasn't been tampered. How that works is that you usually have a central microphone discovery service, and you place this in the middle of your architecture, such that your application does not only, let's say, get the references to the JavaScript, but also gets these integrity values, and then you can instruct the browser to actually use the integrity values, and ensure, therefore, that only if they haven't been tampered with, they will be run. So, quite nice, and the browser will, in this case, block the modified JavaScript because it sees there's a mismatch between what the discovery service said, what was originally uploaded, of course, and what we actually received. And again, it doesn't matter if we received it because there's a problem with the transportation channel, or because someone could tamper with the storage of the files. And for us, it's a good thing. In code form, it might look like this. So, the first part is the response from a discovery service. It tells us the name of the microphone, the version, it also gives us, of course, a reference to it, and then, importantly, gives us the value for the integrity. Finally, if we want now to embed this, we will put it in a script tag, and this wouldn't be hard wired as we see it right here. Of course, this is all done programmatically, but the really critical part is that we use the integrity attribute that is already, let's say, understood from all evergreen browsers, and we are fine. The browser will not block the execution of this file if it detects that the integrity is not fulfilled. Very well, so, another problem has been solved. This is great. There are just so and so many left, but let's look at the problems one at a time, and let's continue with injection, right? As already mentioned, injection is something that you want to have, but you want to restrict it as much as possible, following, of course, the principle of least privilege, that you don't open it unnecessarily wide, but only as far as you need to open it. Now, the attack vector that we see on this aspect is, well, of course, we can construct an attack vector in the browser, but maybe let's shift a little bit here and say we run microformance on the server. Now, here, of course, we have quite some critical attack vectors happening very naturally because, well, everything runs in our, for instance, server, so we might have access there to some SQL database. We might access here to a Redis cache or whatnot. So, many, many resources, the environment variables, which are usually used and, for instance, get the access to something like the SQL database, they are very, very sensitive. So, at the end of the day, what we could say, if there is some code injected, which, for instance, can then read environment variables, could also send it somewhere. Now, we could still argue, maybe we can follow a model like DNO and restrict unwanted HTTP requests, but let's say we are Node.js, we don't have such options. Sure, we could still shield the service, but then there are plenty of other vectors here. So, how can we prevent this in the first place? The answer in Node.js is that we can sandbox using the VM module. Essentially, this allows us to really just determine what things should be accessible from a module when we run it. This is great because then, of course, resources like, for instance, accessing fetch or accessing some third-party dependency that can have access to fetch can be severely restricted, and you don't need to care about any of those. Even better, you can restrict from the beginning on. You don't even need to have access, for instance, to process EMV.
Comments