• Securing Cookies in Go
  • Jon Calhoun
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: lsvih
  • Proofreader: Tmpbook, Yuuoniy

Enhance Cookie security in the Go language

I had some experience with Web development when I started learning Go, but not with cookies directly. Having done Rails development before, I didn’t have to implement security measures myself when I had to read and write cookies in Rails.

Look, Rails does most of the work by default. You don’t need to set any CSRF policies, nor do you need to specifically encrypt your cookies. In the new version of Rails, it does these things for you by default.

Developing with Go is completely different. In Golang’s default Settings, none of this is done for you. Therefore, when you want to start using cookies, it is important to understand the various security measures, why they are used, and how they can be integrated into your application. Hopefully this article will help you do just that.

Note: I don’t want to start a debate about whether Go or Reils is better. Both have their advantages, but in this article I’d like to focus on Cookie protection rather than debating whether Rails or Go is better.

Before we get into Cookie protection, we must understand what a Cookie is. In essence, a Cookie is a key-value pair stored on an end user’s computer. Therefore, all you need to do to create a Cookie using Go is to create an HTTP. Cookie type field containing the key name and key value, and then call the http.SetCookie function to tell the end user’s browser to set the Cookie.

When written in code, it looks something like this:

func someHandler(w http.ResponseWriter, r *http.Request) {
  c := http.Cookie{
    Name: "theme",
    Value: "dark",
  }
  http.SetCookie(w, &c)
}Copy the code

The http.SetCookie function does not return an error, but it may silently remove invalid cookies, so using it is not a great experience. But since it is designed this way, keep its features in mind when using this function.

While this may seem like “setting” a Cookie in the code, we’re actually just sending a “set-cookie” Header when we return a Response to define the Cookie to Set. We do not store cookies on the server, but rely on the end user’s computer to create and store cookies.

I want to emphasize this point because it has a very serious security risk: we don’t control this data, but the end user’s computer (and the user) does.

When reading and writing data controlled by the end user, we need to be very careful with the data. Malicious users can delete cookies, modify the data stored in cookies, and we may even have a man-in-the-middle attack, where someone else tries to steal cookies while a user is sending data to the server.

Based on my experience, cookie-related security issues can be broadly divided into the following five categories. Let’s take a quick look, and the rest of this article will discuss the specifics and solutions for each category.

1. Cookie theft – Attackers try to steal cookies in various ways. We’ll talk about how to prevent and avoid these methods, but at the end of the day we can’t completely prevent physical contact on devices.

2. Cookie tampering – Data stored in cookies can be modified intentionally or unintentionally by users. We’ll talk about how do we verify that the data stored in the Cookie is actually legitimate data that we’re writing to

3. Data leakage – Cookies are stored on end users’ computers, so we need to be aware of what data can be stored in cookies and what data cannot be stored in cookies in case of data leakage.

4. Cross-site scripting (XSS) – Although this is not directly related to cookies, XSS attacks are more harmful when cookies are available to the attacker. We should consider restricting script access to cookies when not necessary.

5. Cross-site Request forgery (CSRF) – This attack is often caused by the use of cookies to store a user’s login session. So we’ll talk about how to defend against this attack in this scenario.

As I said earlier, we’ll address these issues separately in the following sections so that you can finally put your cookies in the safe professionally.

A Cookie theft attack is exactly what it means — someone steals a Cookie from a normal user and then typically uses it to disguise themselves as that normal user.

Cookies are usually stolen in one of the following ways:

  1. Man-in-the-middle attacks, or similar attacks, typically involve an attacker intercepting your Web request and stealing cookies from it.
  2. Obtain hardware access rights.

The ultimate way to prevent man-in-the-middle attacks is to use SSL when your site uses cookies. With SSL, since middlemen cannot decrypt the data, it is virtually impossible for an outsider to get a Cookie in the middle of a request.

You might think, “Ha ha, man-in-the-middle attacks are unlikely…” I suggest you take a look at Firesheep, a simple tool that illustrates how easy it is to steal unencrypted cookies when using public wifi.

If you want to make sure this doesn’t happen to your users, use SSL! Try using Caddy Server for encryption. It can be easily configured and put into production. For example, you can easily get your Go application to use a proxy with the following four lines of code:

calhoun.io {
  gzip
  proxy / localhost:3000
}Copy the code

Caddy then automatically handles all SSL related transactions for you.

Preventing Cookie theft by accessing hardware is tricky. We can’t force our users to use high-security systems, or force them to set passwords for their computers, so there’s always the risk that someone will sit at the computer and steal cookies. Cookies can also be stolen by viruses, such as when a user opens certain phishing emails.

But these are easy to spot. For example, if someone steals your watch, you will immediately notice that it has been stolen when you realize it is not in your hand. However, cookies can also be copied so that no one realizes they are lost.

While not foolproof, there are techniques you can use to guess if a Cookie has been stolen. For example, you can track a user’s login device and ask them to re-enter their password. You can also track a user’s IP address and notify them when they log in from a suspicious location.

All of these solutions require more work on the back end to track data, and more security if your application handles sensitive information, money, or its revenue is significant.

That is, for most applications that are only interim versions, SSL is sufficient.

Face it — there may be jerks out there who suddenly want to take a look at your Cookie and change its value. Maybe he did it out of curiosity, but be prepared for that eventuality.

In some cases, we don’t care. For example, when we define a theme setting for a user, we don’t care if the user changes the setting. When the Cookie expires, the default theme is restored, and if the user sets it to another valid theme we can let him use that theme without causing any damage to the system.

But in other cases, we need to be extra careful. Editing session cookies to impersonate another user can do much more harm than changing a theme. We don’t want to see Joe pretending to be Joe.

We will introduce two strategies to detect and prevent Cookie tampering.

1. Digitally sign data

Digitally signing data — adding a “signature” to the data — allows you to verify its reliability. This method does not need to encrypt or hide the end user’s data. As long as we add the necessary signature data to the Cookie, we can detect whether the user has modified the data.

This method of Cookie protection works by hash coding — we hash the data, and then store the data in the Cookie along with its hash encoding. When the user sends the Cookie to us, the data is hashed to verify whether the hash value at this time matches the original hash value.

We certainly don’t want the user to fool us by creating a new hash as well, so you can use some hMAC-like hash algorithm to hash the data using the secret key. This prevents users from editing both the data and the digital signature, or hash, at the same time.

JSON Web Tokens(JWT) has digital signatures built in by default, so you may be familiar with this approach.

In Go, you can use packages like Gorilla’s Securecookie, which you can use to protect your cookies when creating securecookie.

// 32 or 64 bytes are recommendedhashKey // Set this parameter to "very secret" var for brevityhashKey = []byte("very-secret")
var s = securecookie.New(hashKey, nil)

func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
  encoded, err := s.Encode("cookie-name"."cookie-value")
  if err == nil {
    cookie := &http.Cookie{
      Name:  "cookie-name",
      Value: encoded,
      Path:  "/",
    }
    http.SetCookie(w, cookie)
    fmt.Fprintln(w, encoded)
  }
}Copy the code

You can then also use SecureCookie objects to read cookies in another function that handles cookies.

func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
  if cookie, err := r.Cookie("cookie-name"); err == nil {
    var value string
    if err = s.Decode("cookie-name", cookie.Value, &value); err == nil {
      fmt.Fprintln(w, value)
    }
  }
}Copy the code

The above examples are fromwww.gorillatoolkit.org/pkg/securec….

Note: the data here is not encrypted, but encoded. We’ll discuss how to encrypt data in the chapter “Data Breaches.”

It is also important to note that if you are using this mode for authentication, follow the JWT pattern and sign both the login expiration date and user data. You can’t judge whether the login is valid only by the expiration date of the Cookie, because the date stored in the Cookie is not signed, and the user can create a new Cookie that will never expire, copy the content of the original Cookie to get a Cookie that will always be logged in.

2. Perform data confusion

There is also a solution to hide data and prevent users from faking it. For example, don’t store cookies like this:

// don't do that http.Cookie{Name:"user_id",
  Value: "123",}Copy the code

We can store a value that maps the real data that exists in the database. The Session ID or Remember Token is usually used for this value. For example, we have a table called remember_tokens that stores data like this:

remember_token: LAKJFD098afj0jasdf08jad08AJFs9aj2ASfd1
user_id: 123Copy the code

In the Cookie, we store only the Remember token. If a user wants to forge a Cookie, they won’t be able to. It just looks like a bunch of gibberish.

Later, when users want to log in to our application, they can check the database according to Remember Token to determine the specific login status of users.

In order for this to work, you need to make sure that your obfuscation values have the following properties:

  • Ability to map to user data (or other resources)
  • random
  • High entropy
  • Can be invalidated (e.g. delete or change token value in database)

This approach also has the disadvantage of requiring a database query for each page that the user accesses to verify permissions. This disadvantage is rarely noticed and can be reduced by techniques such as caching. An updated version of this approach is JWT, with which you can invalidate sessions at any time.

Note: Although JWT is currently favored by most JS frameworks, this approach is the most common authentication strategy I know of.

The data reveal that

Another attack vector — Cookie theft, for example — is often needed before a data breach can actually occur. However, it is still difficult to judge correctly and guard against data breaches. Because just because a Cookie has been compromised doesn’t mean an attacker also got the user’s password.

At all times, you should reduce the amount of sensitive data stored in cookies. Never store something like a user’s password in a Cookie, even if the password is already encoded. This article gives several instances where developers inadvertently store sensitive data in cookies or JWT, and since (payload of the JWT) is base64 encoded without any encryption, anyone can decode it.

A data breach is a big mistake. If you are worried that you have accidentally stored sensitive data, I recommend using a package like Gorilla’s Securecookie.

Previously we discussed how to digitally sign your cookies. Securecookie can also be used to encrypt and decrypt your Cookie data so that it cannot be easily decoded and read.

To use this package for encryption, you simply pass in a ‘blockKey’ when creating a SecureCookie instance.

var hashKey = []byte("very-secret"Var blockKey = []byte()"a-lot-secret")
var s = securecookie.New(hashKey, blockKey)Copy the code

Everything else is consistent with the digital signature sample in the previous section.

Again, you should not store any sensitive data in cookies, especially not things like passwords. Encryption is simply a technique that adds some security to data, making it “semi-sensitive” data.

Cross-site scripting (XSS)

Cross-site scripting is also often referred to as XSS, and people try to inject JavaScript code into your site that you didn’t write. But because of the nature of the attack, you have no way of knowing if the JavaScript code running in your browser is actually code provided by your server.

You should always try to block XSS attacks. We won’t go into the specifics of this attack in this article, but JUST in case, I recommend that you deny JavaScript access to cookies when it’s not necessary. You can turn this on whenever you need it, so don’t let it be an excuse for your site to be vulnerable.

This is easy to do in Go, just set the HttpOnly field to true when you create the Cookie.

cookie := http.Cookie{
  // trueIndicates that the script has no permission and allows only HTTP requests to use cookies. // This has nothing to do with Http or Https. HttpOnly:true,}Copy the code

CSRF (Cross-site request Forgery)

CSRF happens when a user visits someone else’s site, but that site has a form that can be submitted to your Web application. Since the end user submits the form without a script, the browser sets the request as a user action, sending a Cookie along with the form data.

At first glance this may seem fine, but what happens when an external site sends data that users don’t want to send? Badsite.com, for example, has a form that submits a request to transfer your $100 to their account, and Chase.com wants you to log into your bank account there. This can result in money being transferred without the end user’s knowledge.

Cookies don’t directly cause this problem, but if you’re using cookies as a basis for authentication, you’ll need to use a package like Gorilla’s CSRF to avoid CSRF attacks.

This package will provide a CSRF token to be inserted into every form on your site. When the form does not contain a token, the CSRF Package middleware will prevent the form from being submitted so that other sites cannot trick users into submitting forms to your site from their own site.

For more information on CSRF attacks, see:

  • www.owasp.org/index.php/C… Forgery(CSRF))
  • En.wikipedia.org/wiki/Cross-…

The last thing we’ll discuss has nothing to do with a specific attack and is more of a guideline. I recommend limiting the permissions of cookies when you use them and only developing them when you need them.

I mentioned this briefly earlier when DISCUSSING XSS, but the general idea is that you need to limit access to cookies as much as possible. For example, if your Web application does not use subdomains, you should not grant cookies all subdomain permissions. But this is the default value for cookies, so you really don’t have to do anything to restrict Cookie permissions to a particular domain.

However, if you need to share cookies with subdomains, you can do this:

C := Cookie{// According to the default Settings of host mode, Cookie is exact domain name matching. // So enable subdomain permissions only when needed! // The following code can make cookies work in any of yoursite.com's subdomains: Domain:"yoursite.com",}Copy the code

For more information about domains, seeTools.ietf.org/html/rfc626…. You can also read the source code here and see its default Settings:Golang.org/src/net/htt….

You can refer toThis stackOverflow problemLearn more about why you don’t need to provide a subdomain prefix when using cookies for subdomains. In addition, you can see in the Go source link that if you provide a prefix, it will be removed automatically.

In addition to limiting Cookie permissions to specific domains, you can also restrict cookies to specific directory paths.

C := Cookie{// Defaults is set to access any Path in the application, but you can also restrict it to a specific subdirectory with the following Settings: Path:"/app/",}Copy the code

And you can also set the path to its prefix, blah /, for example, you can refer to the following article to learn more about this field of method of use: tools.ietf.org/html/rfc626… .

Why don’t I use JWT?

I knew someone would ask this question, so let me explain it briefly.

Many people have probably told you that cookies are just as secure as JWT. But in reality, cookies and JWT do not solve the same problem. JWT, for example, can be stored in a Cookie, which is exactly the same as putting it in the Header.

In addition, cookies can be used for data that does not require validation, in which case it is also necessary to know how to increase the security of cookies.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, React, front-end, back-end, product, design and other fields. If you want to see more high-quality translation, please continue to pay attention to the Project, official Weibo, Zhihu column.