Several Ways of Securing Your API Endpoint
If you’re having a public endpoint, securing it is a must and cannot be considered as nice to have. I would like to share several ways to secure your API Endpoint (Golang will be used for this example), and in this writing we won’t be discussing about any encryption related topic for simplicity. There are some ways to secure your API endpoint using these methods:
- Sanitize any input in your API to prevent malicious script
- Consider limiting your exposed parameter to prevent resource abuse
- Only allow trusted source
- Implement rate limiter
1.) Sanitize Input
As we’re receiving inputs from client, it’s best to think that we cannot trust the payload / parameter given by client. It’s like someone rings a bell on your front door and bring a package to your house, high likely you will peek through the door first to identify if you know the person or asking what his/her intention is, then check what the package is before opening / consuming it.
In your API endpoint, some ways to sanitize your input parameter is to clean up for any malicious script like XSS contained in the payload for example, also using database parameter rather than “concatenating the parameter” as raw string to prevent SQL injection.
bluemonday (https://github.com/microcosm-cc/bluemonday) is an example of golang library that can sanitize input from malicious script.
Please refer to the github / documentation for more detailed usage of bluemonday library.
Talking about preventing SQL injection, let say we got a parameter “username” from our client and we want to search user data based on that with query like
“SELECT * FROM users WHERE username = $usernameFromParam$”
See the code below for example.
If people are submitting “john; DROP TABLE users;” as username and it is being passed down in the getUser function, the database will follow the DROP table command also, meanwhile at the getUserSafe function, the database will search whose username is “john; DROP TABLE users;” literally.
2.) Consider Limiting Some Exposed Parameters
Let say we have our API that allows pagination, in which we expose two parameters, “page” and “limit”. Assuming page parameter will determine on which page the user will like to get data, and limit determines how many data will be loaded on each page. In this case let say we will use the “limit” for our database query, and the attacker can set this value as big as they want, let say 10.000.000, so each time they hit the API, you will get 10 millions data which of course going take a huge amount of load for your database. Long story short, you can implement a simple validation such as if limit > 100|| limit < 1, then limit = 10;
3.) Only Allow Trusted Source
There are some parameters that we can filter out which one do we trust and which doesn’t. One example that is commonly being used by B2B API is that they are whitelisting source of client IP that are allowed to access the API.
Another example is for endpoint that is being consumed public such as web application, we can utilize the Access-Control-Allow-Origin header. If let say We have a website at https://myweb.com, then it will be safer to set the access control allow origin header for that website only rather than allowing all origin via “Access Control-Allow-Origin: *” in the header.
4.) Implement Rate Limiter
You might be wondering if you’re already protecting your endpoint, people can still hit with huge amount of traffic to “overload” your service. In this case, putting rate limiter will likely help. Rate limiting in a nutshell is like a limitation for example, one IP could only hit our API 10 times / second, or for each user session (by cookie / any session identifier), it can only hit the API 10 times / second (the simple idea). If they’re going above the limit you can return error response or some kind. Usually, external load balancer / proxy these days (ie: apache or nginx) already packed with their own “rate limiter” to prevent this kind of attack. It’s possible though to have your own rate limiter in Golang application if you have specific needs in mind. There is a rate limiter golang library that you can use https://godoc.org/golang.org/x/time/rate.
Hope this useful and see you around :)