Tightening source code, in other terms performing Secure code review, is the process organizations go through to identify and fix potentially risky security vulnerabilities in the late stages of the development process. As the last threshold before an app is released, secure code reviews are an integral part of the security process. They serve as a sort of final review to check that your code is safe and sound and that all dependencies and controls of the application are secured and functional.
The OWASP Code Review Guide, penned by Jeff Williams, says it well: “The code is your only advantage over the hackers. Don’t give up this advantage and rely only on external penetration testing. Use the code.”
Basically over the last few decades industry is focusing to handle this in below two approaches -
( Static application security testing)
( Dynamic application security testing )
Security code reviews focus on finding flaws in each of the following areas: Authentication, authorization, security configuration, session
management, logging, data validation, error handling, and encryption.
Several weaknesses (flaws) can affect each of the preceding security mechanisms. Flaws in the handling of passwords often affect
authentication. Flaws related to the type of information included in a message often affect error handling. Flaws in regular expressions often
affect data validation.
Secure code review is probably the single most effective technique for identifying security bugs early in the system development life
cycle. When used together with automated and manual penetration testing, code review can significantly increase the cost-effectiveness of an
application security verification effort
Manual secure code review provides insight into the “real risk” associated with insecure code… A human reviewer can understand the relevance
of a bug or vulnerability in code. Context requires a human understanding of what is being assessed
Nowadays since most of the applications are being written in Golang , lets deep dive into the various methodologies, tools we can utilize to
perform the Secure Code review in an efficient way.
https://github.com/securego/gosec
https://www.sonarqube.org/features/multi-languages/go/
Golang’s adoption has been increasing over the years. Successful projects like Docker, Kubernetes, and Terraform have bet heavily on this
programming language. More recently, Go has been the de facto standard for building command-line tools. And for security matters, Go happens
to be doing pretty well in their reports for vulnerabilities, with only one CVE registry since 2002.
However, not having vulnerabilities doesn’t mean that the programming language is super secure. We humans can create insecure apps if we
don’t follow certain practices. For example, by following the secure coding practices from OWASP, we can determine how to apply these
practices when using Go. And that’s exactly what I’ll do this time. In this post, I’ll show you six practices that you need to consider when
developing with Go
Validating entries from the user is not only for functionality purposes but also helps avoid attackers who send us intrusive data that could damage
the system. Moreover, you help users to use the tool more confidently by preventing them from making silly and common mistakes. For instance,
you could prevent a user from trying to delete several records at the same time.
To validate user input, you can use native Go packages like strconv to handle string conversions to other data types. Go also has support for
regular expressions with regexp for complex validations. Even though Go’s preference is to use native libraries, there are third-party packages
like validator. With a validator, you can include validations for structs or individual fields more easily. For instance, the following code validates
that the User struct contains a valid email address:
One critical and common vulnerability is cross-site scripting or XSS. This exploit consists basically of the attacker being able to inject malicious
code into the app to modify the output. For example, someone could send a JavaScript code as part of the query string in a URL. When the
application returns the user’s value, the JavaScript code could be executed. Therefore, as a developer, you need to be aware of this and sanitize
the user’s input.
Go has the package html/template to encode what the app will return to the user. So, instead of the browser executing an input like <script>al
ert(‘You’ve Been Hacked!’);</script>, popping up an alert message; you could encode the input, and the app will treat the input as a
typical HTML code printed in the browser. An HTTP server that returns an HTML template will look like this:
But there are also third-party libraries you can use when developing web apps in Go. For example, there’s Gorilla web toolkit, which includes
libraries to help developers to do things like encoding authentication cookie values. There’s also nosurf, which is an HTTP package that helps
with the prevention of cross-site request forgery (CSRF).
If you’ve been a developer for a while, you might be aware of SQL injections, which is still number one on OWASP’s Top 10 list. However, there
are some specific things that you need to consider when using Go. The first thing you need to do is make sure the user that connects to the
database has limited permissions. A good practice is to also sanitize the user’s input, as I described in a previous section, or to escape special
characters and use HTMLEscapeString function from the HTML template package.
But, the most critical piece of code you’d need to include is the use of parameterized queries. In Go, you don’t prepare a statement in a
connection; you prepare it on the DB. Here’s an example of how to use parameterized queries:
However, what if the database engine doesn’t support the use of prepared statements? Or what if it affects the performance of queries? Well, you
can use the db.Query() function, but make sure you sanitize the user’s input first, as seen in previous sections. There are also third-party
libraries like sqlmap to prevent SQL injections.
Despite our best efforts, sometimes vulnerabilities slip through or enter our apps via third parties. To ensure that you protect your web apps from
critical attacks like SQL injections, consider an application security management platform like Sqreen.
Just because a string is hard to read, like a base-64 format, doesn’t mean that the hidden value is secret. You need a way to encrypt information
that attackers can’t decode easily. Typical information that you’d like to encrypt are database passwords, user passwords, or even social security
numbers.
OWASP has a few recommendations of which encryption algorithms to use, such as bcrypt, PDKDF2, Argon2, or scrypt. Fortunately, there’s
a Go package that includes robust implementations to encrypt information like crypto. For instance, the following code is a sample of how to use b
crypt:
Notice that you still need to be careful about how you transmit the information between services. You wouldn’t like to send the user’s data in plain
text. It doesn’t matter if the app encrypts users’ inputs before persisting the data. Assume that someone on the internet could be sniffing your
traffic and keeping request logs of your system. An attacker might use this information to correlate it with other data from other systems.
Nowadays, most browsers require that HTTPS works on every site. Chrome, for example, will show you an alert if in the address bar if the site isn’
t using HTTPS. An Infosec team could have as a policy to enforce in-transit encryption for communication between services. So, to secure an intransit connection in the system isn’t only about the app listening in port 443. You also need to use proper certificates and enforce HTTPS to
avoid attackers downgrading the protocol to HTTP.
Here’s a code snippet for a web app that uses and enforces the HTTPS protocol:
Notice that the app will be listening in port 443. The following line is the one enforcing the HTTPS configuration:
You might also want to specify the server name in the TLS configuration, like this:
It’s always a good practice to implement in-transit encryption even if your web app is only for internal communication. Imagine if, for some
reason, an attacker could sniff your internal traffic. Whenever you can, it’s always best to raise the difficulty bar for possible future attackers.
Last, but definitely not least, are error handling and logging in to your Go apps.
To successfully troubleshoot in production, you need to instrument your apps properly. But you need to be mindful of the errors you show to
users. You wouldn’t like users to know what exactly went wrong. Attackers might use this information to infer which services and technologies
you’re using. Moreover, you have to remember that even though logs are great, they’re stored somewhere. And if logs end up in the wrong
hands, they can be used to build an upcoming attack into the system.
So, the first thing you need to know or remember is that Go doesn’t have exceptions. This means that you’d need to handle errors differently than
with other languages. The standard looks like this:
Also, Go offers a native library to work with logs. The most simple code is like this:
But there are third-party libraries for logging as well. A few of them are logrus, glog, and loggo. Here’s a small code snippet using logrus:
Finally, make sure you apply all the previous rules like encryption and sanitization of the data you put into the logs.
With Go’s surge in popularity, it is crucial that Go applications are designed and built with security in mind. Click here to get your copy of the Go
Secure Coding Guide for a deeper dive into the world of secure development best practices in Go, along with many tips, tricks, and code
examples to help ensure the security of your Go. That said, there are a couple of stand out security vulnerabilities commonly affecting apps
written in Go:
Go Metalinter is the TLDR version of this article — if you like the kitchensink approach of giving me everything, go metalinter comes with enough
things to check for all the tools. VS Code installs a good set of tools when it detects that you’re editing a Go project. Here’s how you can run all
the tools that come with metalinter
If you don’t like the shebang approach, I’ll go over some of the tools in go metalinter and others.
Go AST Scanner is a great project for catching security issues like whether you’re using MD5 somewhere or rand rather than crypto/rand
package. That kind of thing.
You can get it running relatively quickly too
Additionally, you can filter by different error types too. If you need to use something that will get flagged by gas, you can use #nosec to avoid the
alert. As usual, it’s always better to add a note on why you’re adding a #nosec for the next person.
Safesql checks against sql injection attacks — particularly helpful in ensuring that some user-supplied data isn’t going to cause SQL Injection
attacks.
Goreportcard is totally a sweet vanity project for me whenever I have an open-source project to check. You can get a web page with the
percentage score for your project based on a few tools.
I have now checked the report for my last significant open source project accord, and it’s dropped to 96%. This may not make your project more
secure in a direct sense, but getting it to 100% will feel good.
One of the tools I love is the go vet tool built into Go, which now breaks your tests as of Go 1.10 which has caught a lot of problems at least at
Mist.
I have never been able to run dingo hunter on a non-academic project with significant complexity but this is a static analyzer to model
concurrency and find deadlocks in Go code, the core code for models is written in Haskell and there’s some pi-calculus math behind it that I don’t
want to pretend to understand.