 Yeah, so hey everyone, I am Ankit Machhala Today I'm going to talk about building a secure BFF which stands for Unfortunately back in for front-end and not best friend forever So back in the day or any one many companies now build services which are complete in itself They are huge servers which handle everything. It might be authentication user team information and everything So clients connect to these servers which have their own database and everything and then figure out everything There's the server handles everything and gives them information. Now. These are termed as monoliths and over time they turn out to be difficult to maintain and have a very comparatively slow release cycle and then people started moving on to Breaking this entire monolith down into smaller services, which are called micro services here each of these service Let's say authentication and user are broken down into separate servers Which have a very well-defined business domain saying you will function in this domain and only give me functions which help modify that data and Then clients will connect to all these micro services fetch information and then show it to the client But the problem here is that now instead of the client connecting to just one Server it has to connect to 10 or 20 different servers based on the number of micro services You have and then act as an orchestrator of various things making it much less performant in order to alleviate this problem The back-ins for front-end servers or gateways came up These are just API gateways designed to act as an interface between client and a server that which consists of Multiple in multiple internal services. So they just sit in between and act as aggregator for all the information So again the client has just one server to talk to this abstract survey all the internal Implementation details of your servers and services from the client making it much more performant as it reduces the network chatter It has less HTTP API calls to make and the same time less network overhead But this kind of service the BFF brings with itself a different kind of security problem and various security concerns What all can we think about just out of your mind? It is a single point of failure and by extension a BFF is a single point of attack It has to it has to be a public-facing service since it is open for everyone to view So you have to implement certain Authentication mechanisms you might also be dealing with user input So you'll have to validate it and all these are pretty ad hoc And so is there a generic way in which we can quantify these concerns for an API in our case a BFF? It turns out there are very broad parameters described for evaluating security of any given system And most of you might already be aware of this first of them being Confidentiality meaning the data is only available to authorized users and not being leaked to someone else who is unauthorized Then we have integrity meaning the data is not tampered with by unauthorized sources and finally we have availability Meaning the data is available to authorized users when they want meaning you are able to access things which are allowed to as in when you please Now these parameters Give us broad thinking silos under which we can think about security of an API specifically and in our case a back-end for front-end So to better understand the BFF. Let's break the entire service down into four individual modules One of them being service inbound platform and outbound We'll talk about these individually and see how we can secure each of these modules and Think about how they all combine together at the same time I would also like to tell you about what things we did at postman to edge to build a secure back-end for front-end for our web application So let's start with service, which is where all your server side logic resides This is where you or your controllers will decide your business logic for the BFF will be there a request first hits this module and You would think that if the request is hitting this module that obviously we'll have to perform some sort of validation But not all validations can be performed on a BFF Only ecosystem level checks should be performed on on such a service now these include Checking whether a quest has valid authentication if it has proper request structure or maybe if sanitize certain headers for you But but all the business logic specific checks say for example can a user Comment on this specific document all these checks are handed over to a specific microservice Which is responsible for this specific case but For some of these validating functions, you might be calling third-party services or maybe your internal microservice For example, if you want to check for odd, you might be calling odd zero Maybe google.com to verify is is the given request authorized or authenticated and All these services which are called before a request hits your business logic Constitute the critical path and This critical path the length of this gives you a rough estimate as to how complex the validations are on your BFF It's generally a good idea to keep this short and also have necessary fallbacks for non essential services Keeping your BFF much more available and at the same time much more performant But how do you write these validating functions? I keep talking about these red blocks on your screen and for that the principle of least privilege comes in very handy Very for any action a user wants to perform you give only the minimum resources required This means that you start off by giving no permission at all and assume that the user is not allowed to do this And then for very specific conditions allow this action to be performed So let's take a very trivial example to understand this So you are building a function called has access It takes into arguments user and the owner Which is the user and the owner and if a job of this function is to check if the given user has access or not So the first thing you should be doing in any such function is return false that by default User does not have access and then start adding one by one your cases saying hey, is the user an admin then? Okay, allow access is the user the owner then also you allow access So what you are doing is that only for these two specific conditions? You are allowing the request to pass through and and for all other cases It will fall failover to a false case now This is called a fail early or a fail first approach of writing functions or writing any sort of code And this also prevents against data corruptions like say for example the is admin is not an it's not a boolean But it's undefined in that case. It's also it will fall through and return false protecting your internal business logic against unauthorized or even malformed requests Now This was a very very contrived example Let's look at a much more involved example, which has a sample BFF and see what we can do so here I am in a simple Server which has multiple routes which might happen in any public service. So it has certain open views which are The dash the landing page sign up page login which have to be open It has certain dashboard pages which are only allowed for authorized users certain api endpoints and finally certain redirects And this is how any standard public website or an api will have so and everything is open right now I can just refresh it and see I can I do get everything what I have That is because in the functions with check for access. Nothing is defined now in this file If I write all my validating functions, they might be middlewares. They might be certain accessor functions, so We always start off by writing for any route or for any endpoint you hit you return false That's it. Nothing else Refresh forbidden that means you start off by putting the maximum restriction any endpoint you have in this Api will not be authorized and then you start off by relaxing constraints. So for dashboard That is a dashboard controller. Sorry the entrance Which is open to everyone you say any anything within the entrance Controller or in the entrance page you allow everyone because it has to be open your pub your website has to be visible There you have it. I can simply click on login The type a And sign in but still I got forbid I signed in the the password was correct The username was also correct, but I still haven't explicitly given permissions to users who are signed in so let's do that So for the dashboard, which is our signed in page We say any request within these this dashboard module will be or controller will This is not a Boolean answer this you cannot say allow or disallow You have to say check for login and for that I've already written a helper method called is logged in and this will check for anything within the dashboard and I'm also copying it over for the account Page saying that you allow all logged in users. So I refresh it. I try to log in again Password and Sign in and there we have it our page But when I again when I try to go to the team section I haven't explicitly given permissions and you know the drill by now for any new endpoint or any new route or set of routes You add you start off by giving applying maximum constraints So for the team controller apart from checking if you are logged in or not, you also check I'm sorry is logged in you also check is Super admin meaning all the routes in this Controller that is team are only allowed for admin users But for some of these things they might be only available for everyone So that's a team information should be available to all the users and for that we relax constraint for that specific endpoint call it info and say for this endpoint you Relax to just is logged in so what you see the drill by now is that you start off by putting the maximum constraint Don't allow anything and relax for only specific endpoints which use deem necessary and by this way you are protecting against a developer Randomly adding a endpoint and forgetting to add correct access control so this very this idea idea of Differentiating the access control from my business logic remember I never touched my controllers all I did was touch my policies which are Accessor functions and nothing else was changed is Highlights the fact that you need to use your architecture of an API as a forcing function What that means is make it harder for your developers to be insecure One of the way in which we do this at postman is to separate our entire business logic from access control You saw a very tiny example of that. We also leverage our platform or our framework So at postman we heavily rely on sales. Yes, which is built on top of express And provides this concept of hooks wherein you can augment the framework itself to improve functionalities So we implement things like oath hook which takes care of all the authentication requirements for a specific API So and all these things are baked in whenever a new service spins up So the developer when starting to work on doesn't have to worry about all these small Litigrates which may fail or which where a developer mistake might be very critical It also comes in with all the dependencies bundled in Now a very important fact to note is that you are not going to write all your code You are going to reuse a lot of modules may be npm or from yarn And it's crucial that you start off by using strict versions for whatever dependencies you use So you verified your app and checked for security with point one of let's say version point one of request module And you are guaranteeing security for only that specific version It should not be deployed with point one dot one because it may or may not have a security vulnerability Which you are not even aware of so you strict file versions and also lock files to ensure prevent deep dependency updates But it might be possible that you checked for point one today. It is completely secure But tomorrow a security researcher came up and say hey There is a huge vulnerability with this and for that you constantly need to monitor whether your dependencies are vulnerable or not and for that you use tools like nsp npm audit, which is built into npm And also sneak which we use to for our source for our dependency analysis So here's a sample sneak test command. It just checks all your dependencies And it gives me a list of saying hey I find two of these things here, which is medium severity vulnerability. It tells me it's a read-off type attack You it is introduced via some package and you can do this to resolve the dependency And this is integrated into our CI pipeline and run on every branch build Meaning that even in case The developer wasn't aware of certain mistakes or certain vulnerabilities in the dependency It will be easily caught and you can take the necessary steps So this was one way of enforcing security while building something There are other ways which we do it at postman and one very simple way which is often overlooked is Linting for security. Let's take a very quick example and understand So here I have a link which is external because it has a target underscore blank Now this is unsafe because the external tab which is opened has access to my current tab with the window.referrer Object and can redirect me to anywhere else making it insecure So linter catches this and tells you that hey, this is not allowed You need to add rel no opener no referrer to make it to prevent the open tab to have access To your current tab these are very simple mistakes extremely simple mistakes Which are easily caught by linting not using eval or certain function Function types which prevent you from making small mistakes and they go a long way in securing your application We have system tests to ensure configuration of critical packages. Let's say if you're using an Auth package which has to be configured in a certain way This the system tests are extremely thorough and very fine to the last detail if that package was configured correctly And any change in this system test acts as a red flag for our code reviewer saying that hey Something major was changed here be very careful while you are reviewing this and finally we have e2a tests for security Especially using postman collections. Oh, let's let's take an example of how we do that So I'm back here in the postman app and just resize things. Yep Now we are using the same BFF which we started off with if you remember I added certain Policies which were here. I added these policies which a check for certain access now I have built a security collection which is Reproducing a user information leak. So let me just maximize this for you So what I'm trying to do here is I'm logging in with user ID for Then get trying to get information of user ID for using this API endpoint saying API slash V1 users user ID to or user ID for and I'm then I'm also trying to fetch user force information That is the the difference that I'm trying to fetch information of two users I'm authorized as user for but I can only access user User force information not someone else. So let's go ahead and test this new man run security collection Do run so now it complains saying that hey, I'm trying to access User force is trying to access user twos information and it should return 403 I wrote these tests here in the test script that I'm trying to That I should check for a specific response code these tests can be much more complicated That means this is an actual failing test case provided to me by anyone in my team saying that hey This is a bug. This is how you reproduce it. Go ahead and fix it. So let's do that. So the problem here is that Instead of taking the user ID from the path we take it from the authentication mechanism So we all we verify that say for account the user should be logged in at the same time It should have the a valid user ID That that this will check the user ID from the path and compare it with what we have gotten from your authentication method And when I try to run it, it should pass because now this is where you have a failing test case You fixed it and you integrate this command new man run collection It's just running a collection and integrate that into a CI pipeline as a regression test Making it very easy for anyone inside our team as well as People who work on who are not a part of our team building the BFF to give us a failing test case Reproduce an issue which we which can be easily integrated into a regression testing pipeline Now this was all what we discussed were writing the code on BFF on an API but a major chunk of a BFF is to talk to internal services, which was its core purpose and The first hurdle in this case is to handle authentication for internal services Now some of your services might have basic authentication. Some might have token authentication Some might rely on cookies or everything in the world But all these things are abstracted away from the developer and especially from the server side code So here's a sample snippet from one of our controllers So instead of developer manually specifying the base URL of the service and the authentication mechanism All they do is they provide the service name, which is service auth which path to hit and what queries to pass This abstracts away all the information about authentication information about What is what are the internal implementation details of those servers and also prevents accidental leaks So when I was querying a service without this abstraction I might there is a high chance of me either logging that internal auth mechanism or also returning see client secrets via my API endpoint. It also allows for easier secret rotation Since your service server side code does not care about how you're authenticating It is taken away. You can rotate your server side secrets without even touching your server side code and when you're dealing with all these services that Authentication as you have learned in previous talks that authentication is just not enough You also have to validate whether a person is authorized to perform something So for that we tag each request coming to our BFF and sent on to our internal microservice With a certain token. So here our BFF is adding a sample token It might be an access token or a session token which allows the internal service to Identify that who is the user performing this action and what other checks I need to implement in this case For example, only admins can remove users from team and this token allows the internal service to get the user information Check whether they are admin or not and allow or disallow based on that This helps us in preventing a major class of vulnerabilities, which fall under the name I door It stands for indirect object referencing this happens when you expose internal object references like let's say auto increment IDs along with Incorrect or inappropriate access control checks. We saw an example of this When I demo demonstrated user for trying to access user twos information So here's the same example that the user is authenticated ID one two three But since the API does not have valid checks I also was able to obtain user one two fours information and an attacker can enumerate through all these keys and There you go. You have had just had a major breach So these every user action needs to be validated against the token which you have passed So in this case, it would mean that verify the user ID in the query The path is the exact same we fetch we get from the token preventing this issue and Apart from preventing user leaks You would also be logging a lot of things because this is a BFF It talks to so many internal microservices. You might need to log it for analytics It might be for let's say debugging purposes and since you might be dealing with user-sensitive information Maybe or the password email. Maybe credit card information You have to scrub your logs for sensitive information And of course it is expected from developers to not log information which is considered sensitive But we also have heuristic functions in place which Redact certain information from the logs. So here we have a service a which is trying to log Authentication that is the token ID, but instead our functions Okay, our functions try to functions detected that hey access token is trying to trying to be logged Redacted completely and don't do it This allows us to also trace our logs throughout our internal network So we attach a trace ID with the request originating from the BFF and then Trace it throughout our internal microservices infrastructure giving us a track of potential PII movements Which is personally identifiable information since this is a user service any service you call might also be dealing With user information and you need to check that if they are also in compliance with the rules and regulations you follow So this was all about building your server side code that you Wrote your logic in certain language you talk to internal microservices using certain practices but at the end of the day you have to return all this result to the client and this is where our traditional security Terms come in SGTPS CSP SRI and I'm going to skip over all this and just talk about two specific things Interesting things about we learned while building a BFF at postman first of them being SGTPS When switching to SGTPS you will always be choosing a type of certificate your cloud provider might be giving a default certificate You might also obtain a free certificate from services like let's encrypt. They provide domain validation, but these Certificates ensure that the domain you are seeing in the URL that the data served by them is exactly what you are getting However, they do not validate the intent of the content serve You can be served malicious content over a secure channel and if you want to instill more trust So let's say you are building a very critical payment service You might want to instill more trust in your users and for that you might opt for extended validation certificates Where in your organization is also validated by the certifying authority and the user is given more information saying that this company was authorized And when you are transitioning to SGTPS Please ensure and constantly monitor that all your requests and everything are tagged Are over SGTPS and they are not And they are not falling back to a insecure channel and finally once you are verified that everything is done You can opt in for a stricter saying that HSTS my service is only allowed over a secure channel And be very careful while doing this You might end up in a place where if you want to downgrade to SGTPS for something and you have pre-loaded it into browsers It will be very very difficult to fall back Now once you have served secure content and ensure the user that this hasn't been tampered with You you also want to see that only specified things are allowed to execute in your Application this is where content security policy comes in now It provides a whitelist of things saying that only allow things from these sources to execute and don't allow things from us When you start implementing CSP always start by implementing in report only mode It helps you a lot in this mode CSP won't block anything It will just report to a URI you provide saying that hey these violations were reported and then You will never handle and then you won't have to worry about side effects So for example, you might be using services like Google Tag Manager. They inject JavaScript dynamically and you might break your entire analytics pipeline if you disable blindly all inline JavaScript And finally you need to be very careful that I understand that CSP isn't an ideal candidate for data exfiltration Once there is malicious JavaScript in your server or in your application You cannot rely solely on CSP to prevent misuse of that attack misuse of that data for example link hrefs are not covered under CSPs and there are a whole other plethora of Security headers which you can refer to and pick and choose what suits your needs and what you need to do but in all these Jumbled words and headers which you need to use one thing which is which stands extremely crucial is that all of these checks are dependent on the browser the Client is using so if a browser does not support CSP all your fancy rules are going to go down the drain and they are definitely not a replacement for careful input validation and Output encoding you have to be very careful while taking an input to your server sanitize it and do the exact same when you are showing it to the user and This completes building our application layer. We built everything securely. We we took care of in Internal validation outbound so the talking to our internal services and also showing it to the client But we are going to serve all these things over a platform It might be AWS Azure or digital ocean and since you are not exactly building a server from scratch from actual hardware You are configuring certain third-party services Which mean that you have to have constant audits and automation to to protect your cloud infrastructure So what do you audit you audit for developer access saying only a set defined members are allowed to do certain Things you check for configuration when you set up things saying am I setting up with the appropriate values? is it Insecure in any way and also ensure that resources are created with reliability when they are when they are done over time So it's a you are creating various instances you need to ensure that those instances are created reliably and securely every time For that at postman we use our collection runs to create resources with extreme confidence So once if we have guaranteed that we have created a database securely a collection run guarantees That it will be secure in every future run and we also Monitor these configurations every time using our monitoring service and keeping a track of what exactly happens And if anything major is found missing or something is misconfigured We are notified and then we take appropriate steps So let's take a look at how we perform one single audit with with a collection so I'm back in the postman app and I have a collection ready for you, which is AWS MFA audit this collection does one simple thing It lists down all all the user in your AWS team Verifies if all of them have MFA enabled that is two-factor authentication enabled and so I just go ahead and run this collection I will choose the appropriate environment and then say run Now this will call the AWS API with your access token fetch the users. I hope the internet works and fetching users users users and It won't return because if your internet does not work you won't be able to list users But ideally what you will have is if you open the runner you will have a result like this Which is already ready for you, which tells me the last line saying Ankit underscore M should have MFA enabled Which is exactly what I want. I want to verify that all users in my team have MFA enabled This keeps on running constantly and if anyone does not have to F enabled we get a slack notification We notify them and everything is good One other thing which we ensure in our platform is health check Once your service is ready for deployment and before it is being served to actual live traffic in production We verify for mission critical information. This might be things like keys environment variables DB consistency your cash consistency all the things which you know might affect the availability of your service and In our applications, we have a bootstrap test which performs all this and if anything fails in this step We just go ahead bail out and prevent the deployment and if it everything looks good then yes, you are allowed to deploy and However, this is used as a last step of it's the last line of defense Preventing against major mishaps and it is definitely not to be used as a testing mechanism for anything So you all built you we all talked about about each Components which come into building a secure back-end for front end We started off with the service handled validation in inbound where we talked to our Intel microservices Ensured that content was served securely to our clients and also Secured our platform which serves all these resources But we it's not a one-time thing that you do all these things once and forget it You need to ensure that these things are continued and your application stays secure over time and that is where you we perform certain Software we follow certain methodologies to ensure that our services stay secure One of them is tracking security KPIs KPIs stand for key performance indicators And one of them is CVSS scores of the vulnerabilities. We detect we track them throughout our versions We see how often we are repeating our mistakes or are we repeating our mistakes? How long does it take to fix a issue reported by users or maybe someone from our team? It and also keep a track of issues reported by services like hacker one which are very security researchers Try to break your app and these are tracked throughout our versions Giving us a very quantifiable metric that whether your BFF was secure or not or has it dwindled over time Or has it become more secure over time and this is all handled in a step called VAPT It stands for vulnerability assessment and penetration testing. This is a post-development step where we're in Once a build is ready for production deployment. We send it to our security team They perform certain tests on that it might be White box or black box testing and try to find vulnerabilities or security issues with the build if they find any They suggest changes to us and we make them change make changes and send it back again And once it is cleared by them it only then it is allowed to go to production And this step it also exists in most of the companies and is a very tedious process and very manual Because the the engineers have to manually try for every keeper track of all past All past bugs Try them again saying have you not have you don't regressed for something? But at postman we automate all these things using our collection runs as you just saw I demonstrated three different ways to check for various things. Now any bug you find let's say a User information was leaked a collection is created and is automatically run whenever a build is sent to this security step Keep making this process much more faster and also reliable eliminating human error from this and All these things building a secure platform a Secure API layer and following so proper software methodologies ends up in building a secure API or a BFF in this case So we started off with if you remember we started off with certain security parameters saying that we want to evaluate security of our BFF Under these parameters What all did we do to achieve those things to achieve confidentiality? We we ensured proper validation using principle of least privilege. We scrubbed our logs using various Euristic methods to ensure integrity We made sure that every request was tagged with the user information so that we prevent IDOR attacks and leaking informations about other users and also implemented cut-edge security using various headers and Finally to ensure availability We kept our critical path extremely short Meaning our BFF is much more performant We performed constant platform audits and also consistent health checks to ensure that a bad release isn't pushed out to users and All these things combined to build a secure API in general and this is what you need to take care While building anything that your needs might be different from our needs a certain things you fell right for us And we had certain use case in mind But your API or your BFF might not have those constraints or might not have the same use case So what you need to understand is what security considerations you need to take care while building each module of your API and also Keeping in mind that it is a gradual process. You can't wake up one day. So today I'll build my API secure It's not going to happen in a day It will happen over time where you constantly monitor for things you measure things and ensure that your API remains that way throughout the period of time and finally, it is it is very very interesting and very Philosophical to say that security is ingrained in you But small mistakes which you make let's say using eval or using unsafe links They go a long way in destroying the security for an application So while developing make sure you take care of these small mistakes You ingrain security as a part of your development process and don't wait for QA or security engineers To tell you that this is wrong which goes a long way in building a secure and also reliable back end for front end Thank you very much