Introduction to secure coding in Golang
The first rule of computer security is
“Don’t buy a computer and if you buy one never turn it on.”
Security is one of the most important aspect of software development, every day we get to hear news of data leaks even at prominent MNCs, like what happened with Log4j the other day, a package in place for 21 years with so many vulnerabilities.
This clearly shows no process, procedure or ideology can guarantee 100% security but being a little cautious while developing can of course protect us from some trivial and known security flaws.
I don’t feel too proud to say this but for us developers, security is usually the last step of our SDLC. Systems are usually not developed keeping in mind the security rather based on some penetration testing or literally breakdown later on , we refactor our code.
Security as a step is important for all the components of a computer system, be it backend services, frontend layout, infrastructure or whatnot. But I being a backend developer is going to talk about backend per se.
Well as the title suggests we are going to focus on Golang based checks which might enhance our code security but yes, in general, these principles apply to all the languages and frameworks, of course, the implementations might vary.
Input Issues
The most basic component of a backend service through which it communicates with other components of a system is an API. API is like THE word of backend engineering.
So let’s try to understand what an API is.
Well, API expands to Application Programming Interface. To understand it in layman terms, think of yourself as a customer in a restaurant and the kitchen of that restaurant as a system. The system has the food you need but there’s no direct way through which the system will know what you need and how can it serve you what you need as a customer, this is where the waiter comes in, our API.
Simply, we give instructions to the waiter and he fetches the required stuff from the system for us.
So the flow is usually like this, we give input to the API and it gives us an output based on the system.
The typical flow for a system to process input is

Well, what happens if the input given to me is too large that while loading it into the memory my application breaks. Well, we can define checks at the network layer but there are malicious XML like these:-
̂<?xml version=”1.0"?><!DOCTYPE lolz [<!ENTITY lol “lol”><!ENTITY lol2 “&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;”><!ENTITY lol3 “&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;”><!ENTITY lol4 “&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;”><!ENTITY lol5 “&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;”><!ENTITY lol6 “&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;”><!ENTITY lol7 “&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;”><!ENTITY lol8 “&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;”><!ENTITY lol9 “&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;”>]><lolz>&lol9;</lolz>
which might just expand to GBs. Okay, so this is an issue, right?
Well, not exactly we can use the LimitReader function() of the io package. Some serialization formats like zip and xml expand to too large sizes but thankfully for us the standard library protects us in that case, but we should always mark caution while unmarshalling data especially from external sources.
Two fallacies in distributed networking are:-
- Network is reliable
- Latency is 0
The network can be laggy and might be keeping the connection open for a very long time, or maybe the request body is too large or the API triggered a query that is taking too long to resolve.
Timeouts in HTTP handlers come in handy in these cases, well most services are exposed via load balancers and they usually handle it but it isn’t too bad to be extra cautious.
httpHandler := &http.Server{ Addr: ":" + "9876", Handler: router, ReadTimeout: 1 * time.Second, WriteTimeout: 1 * time.Second, IdleTimeout: 10 * time.Second, ReadHeaderTimeout: 2 * time.Second,}
Output Issues
Well, we don’t have to be cautious about just what’s entering our system but also how we process it and send it over to our client.
Some very common scenarios are
- XSS(Cross-site scripting) :- Well it’s one of the most common forms of attacks on trivial JS based UI. Rogue elements pass some JS script to the server which when forwarded to UI triggers an unwanted process. To mitigate it best approach is to use either EscapeString function of HTML package just use template package to generate HTML
- Termination of HTML Handler :- Go doesn’t have exception handling, http.Error doesn’t end the controller you have to explicitly return from the controller. Well if this little detailing is missed it can very well expose a lot of unwanted data or services.
Process
To make our HTTP server more secured we can switch from the ListenAndServe to ListenAndServerTSL which makes it more secure
Security is not a step but a complete journey in itself which is forever evolving, it has to be inculcated at each step of SDLC to ensure safety and security.
We can always put it
Processes at Dev Level can be using linters like gosec or golang-ci, especially in CI pipelines (like GitHub Actions) to identify any potential vulnerabilities.
Security Audits is also a good approach, but audits are required at not just code level but design levels as well. It’s pertinent to check logs and monitor service alerts as well time to time for the same.
Well I had been babbling about security but most developers might have identified this with the role of an Ops team performing Penetration Testing on their systems and yes penetration tests are very helpful but it isn’t too bad extra cautious at times.
Well, these were my thoughts, I would appreciate if you can share yours through comments. Till then “Au Reviour”.