How do I prevent cookie modifications from the browser? How can I sign cookies to prevent malicious updates to them?
search cancel

How do I prevent cookie modifications from the browser? How can I sign cookies to prevent malicious updates to them?

book

Article ID: 166142

calendar_today

Updated On:

Products

ProxySG Software - SGOS

Issue/Introduction

A cookie is text in an HTTP or HTTPS header that contains data about a user's preferences, authentication data, or other session-specific information. This text is placed on a user’s computer when the user accesses a website that uses cookies. Because HTTP cookies are not encrypted, they are vulnerable to users with malicious intent who may tamper with them. 
 
You can sign cookies to prevent them from being compromised. A digital signature validates cookies and verifies that their content is unaltered.
 
Note: If you manage multiple ProxySG appliances, each of the appliances must have the same cookie signing key. Use Director to synchronize this key across all appliances.
 
To prevent malicious updates to the cookies stored by browsers, complete the following tasks:
  1. Determine the application cookies to be signed.
  2. Update policy to sign cookies.
  3. Prevent cookie replay attacks.

 

Task 1: Determine the Application Cookies to be Signed

Before you can add policy for signing cookies, you must determine what cookies will be signed.
  1. Create a list of the applications that create cookies or require cookies.
  2. Determine whether the cookies can be signed, or if they should remain unsigned. Some applications may not function correctly if cookies are signed. 
  3. Determine a base policy that is appropriate for your deployment, and update the policy accordingly. Your deployment likely requires one of the following policies:
    • All application cookies are signed and any unsigned cookies are deleted. See Sign All Cookies.
    • All application cookies are signed, but there are some exceptions where the application cookie is not signed. Any unsigned cookies that are not specified in the exceptions are deleted. See Sign All Cookies with Exceptions.
    • No application cookies are signed unless they are from a specified application. Any unsigned cookies from the specified application are deleted. See Sign Only Specific Cookies.

 

Task 2: Update Policy to Sign Cookies

If you update policy to sign the cookies with a digital signature key and delete unsigned cookies, users with malicious intent will be unable to modify or replace cookies.
 
In the policy samples in the following procedure, the original HTTP response contains the following information: 
 
Set-Cookie: A=a;domain=.x.com:path=/
Set-Cookie: B=b;HttpOnly
Set-Cookie: C=c;Secure
 
The original HTTP request is not aware of the cookies. Any future requests (prior to the cookie expiring) contains the following text:
 
Cookie: A=a
Cookie: B=b; C=c

Sign All Cookies

All cookies generated by the application are signed without exception. Any unsigned cookie that the application attempts to use is deleted automatically.
 
Add the policy to sign all application cookies. 
In the following sample policies, all cookies will be signed. 


SGOS6.4 code sample
define action sign_all
     iterate(response.header.Set-Cookie)
          iterator.append("$(iterator):rewrite(([^=]*)=([^;]*)(.*),BCSIG_$(1)=$(2:hmac)$(3))))")
     end
end



SGOS6.5 code sample
define action sign_all
     iterate(response.header.Set-Cookie)
          iterator.append("$(iterator:rewrite(([^=]*)=([^;]*)(.*),BCSIG_$(1)=$(2:hmac)$(3)))")
     end
end

<Proxy>
      server_url.domain=x.com/ action.sign_all(yes)

In the samples above, x.com is the URL of the application. For example, modify the policy to server_url.domain=bluecoat.com.
Note: all other code samples will work for SGOS 6.5 and SGOS 6.4
  1. Add policy to delete any cookie that is unsigned. 
    In this sample policy, all unsigned cookies will be deleted.

    define action delete_all_unsigned_cookies
        iterate(request.header.Cookie)
          ; Delete the signature cookies
          iterator.prefix="BCSIG_" iterator.delete()
          ; Delete any cookies without a matching signature cookie
          request.header.Cookie.exact=!"$(iterator:rewrite(([^=]*)=(.*),BCSIG_$(1)=$(2:hmac)))" iterator.delete()
        end
    end


    <Proxy>
      url.domain=x.com/ action.delete_all_unsigned_cookies(yes)


    In the sample above, x.com is the URL of the application.
    If a large number of site URLs need the same signing policy, define a URL condition to simplify policy creation.

    Note: You must add policy for each application that has a different url.domain.
     
  2. Install the policy.
    The resulting HTTP response indicates that all cookies have been signed:
Set-Cookie: A=a;domain=.x.com:path=/
Set-Cookie: B=b;HttpOnly
Set-Cookie: C=c;Secure
Set-Cookie: BCSIG_A=signature_code(a);domain=.x.com:path=/
Set-Cookie: BCSIG_B=signature_code(b);HttpOnly
Set-Cookie: BCSIG_C=signature_code(c);Secure 

Sign All Cookies with Exceptions

Some applications require cookies to be updated as users interact with the application. These types of applications may not function correctly if the cookies are signed. 
 
Use this policy when most of your cookies must be signed, but a few cookies should remain unsigned. Any unsigned cookies are deleted, but the unsigned cookies specified in the policy remain on the system.
 
  1. Add policy to sign all cookies except for B and C cookies.

    define action sign_all_but_B_and_C
         iterate(response.header.Set-Cookie)
              iterator.prefix=("B=", "C=")
              iterator.append("$(iterator):rewrite(([^=]*)=([^;]*)(.*), BCSIG_$(1)=$(2:hmac)$(3)))")
         end
    end

    <Proxy>
         server_url.domain=x.com/ action.sign_all_but_B_and_C(yes)


    In the sample above, x.com is the URL of the application. 
     
  2. Add policy to delete all unsigned cookies except for B and C cookies.

    define action delete_all_unsigned_cookies_except_B_or_C
        iterate(request.header.Cookie)
          ; Delete signature cookies
          iterator.prefix="BCSIG_" iterator.delete()
          ; Skip Cookies B and C
          iterator.prefix=("B=", "C=")
          ; Delete any other cookie without a matching signature cookie
          request.header.cookie.exact=!"$(iterator:rewrite(([^=*])=(.*),BCSIG_$(1)=$(2:hmac)))" iterator.delete()
        end
      end

    <Proxy>
        url.domain=x.com/ action.delete_all_unsigned_cookies_except_B_or_C(yes)


    In the sample above, x.com is the URL of the application.
     
  3. Update the line iterator.prefix=("B=", "C=") to specify the cookies that should not be signed and the specific unsigned cookies that should not be deleted. This line should be the same in the signing policy and the deleting policy.

    Note: You must add policy for each application that has a different url.domain.
     
  4. Install the policy.
    The resulting HTTP response indicates that all cookies except B and C have been signed:
Set-Cookie: A=a;domain=.x.com:path=/
Set-Cookie: B=b;HttpOnly,
Set-Cookie: C=c;Secure
Set-Cookie: BCSIG_A=signature_code(a);domain=.x.com:path=/
 
Future HTTP requests contain the following text, which indicates that all unsigned cookies except cookies B and C have been deleted:
 
Cookie: A=a
Cookie: B=b 
Cookie: C=c 

Sign Only Specific Cookies

If your application generates multiple cookies, but only a few contain sensitive data or can access the system, leave the majority of the application cookies unsigned and specify the cookies must be signed. All unsigned cookies are deleted automatically, except for cookies specified in policy.
  1. Add policy to only sign B and C cookies.

    define action sign_only_B_and_C
         iterate(response.header.Set-Cookie)
              iterator.prefix=("B=", "C=") iterator.append("$(iterator):rewrite(([^=]*)=([^;]*)(.*),BCSIG_$(1)=$(2:hmac)$(3)")
         end
    end

    <Proxy>
         server_url.domain=x.com/ action.sign_only_B_and_C(yes)


    In the example above, x.com is the URL of the application.
  2. Add policy to delete all unsigned cookies, except for B or C cookies. If the B or C cookie is unsigned, it will not be deleted.

    define action delete_all_unsigned_cookies_except_B_or_C
        iterate(request.header.Cookie)
          ; Delete signature cookies
          iterator.prefix="BCSIG_" iterator.delete()
          ; Delete cookie B or C if they don’t have a matching signature cookie
          iterator.prefix=("B=", "C=")
          request.header.cookie.exact=!"$(iterator:rewrite(([^=*])=(.*),BCSIG_$(1)=$(2:hmac)))" iterator.delete()
        end
      end

    <Proxy>
        url.domain=x.com/ action.delete_all_unsigned_cookies_except_B_or_C(yes)


    In the example above, x.com is the URL of the application.
     
  3. Update the line iterator.prefix=("B=, C=") to identify the specific cookies to keep if they are unsigned. This line should be the same in the signing and deleting policy.

    Note: You must add policy for each application that has a different url.domain.
     
  4. Install the policy.
    The resulting HTTP response indicates that only cookie C has been signed:
Set-Cookie: A=a;domain=x.com:path=/
Set-Cookie: B=b;HttpOnly
Set-Cookie: C=c;Secure
Set-Cookie: BCSIG_C=signature_code(c);Secure 
 
Future HTTP requests contain the following text, which indicates that cookie B has been deleted because it was unsigned, but cookie C remains on the system:
 
Cookie: A=a
Cookie: C=c 
 

 
 

Task 3: Prevent Cookie Replay Attacks 

A cookie replay attack occurs when users with malicious intent use authentication information from cookies to access applications. For added protection, you can write policy to verify and reject cookies that have been replayed.
 
In policy, add one of the following after the text "$(2":
":concat($(client.address))" 
":concat($(user))"
 
Depending on factors specific to your deployment, such as the number of mobile users and if users are authenticated against the ProxySG appliance (for example, a SAML realm is configured for the appliance), you would specify either the client address or the username as described in the following sections.

Using the Client Address

If users are not authenticated against the ProxySG appliance in your implementation, you can specify the client address to protect against replay attacks. With this policy, the appliance rejects cookies that don’t come from the client IP address to which the cookie is originally issued.
 
The following policy specifies the client address:
 
define action delete_all_unsigned_cookies
     iterate(request.header.Cookie)
          iterator.prefix= "BCSIG_" iterator.delete()
          request.header.Cookie.regex=!"$(iterator:rewrite(([^=]*)=(.*),BCSIG_$(1)=$(2:concat($(client.address)):hmac)))" iterator.delete()
     end
end
 
define action sign_all
     iterate(response.header.Set-Cookie)
         iterator.append("$(iterator):rewrite(([^=]*)=([^;]*)(.*),BCSIG_$(1)=$(2:concat($(client.address)):hmac)$(3))")
     end
end
 
The policy doesn’t prevent replay attacks where the replayed cookie’s address has been forged (spoofed) to match the original cookie’s address.

Important Note About This Policy

The client.address policy deletes any cookie that doesn’t come from the same IP address to which the original cookie was sent, and is thus inappropriate for mobile users whose IP addresses changes frequently. The policy might also be less effective than intended in Citrix environments, where many users share the same client IP address.

Using the Username 

If users authenticate against the ProxySG appliance, you can specify the username to protect against replay attacks. With this policy, the appliance rejects signature cookies whose user credentials don’t match those in the original cookies.
 
The following policy specifies the username:
 
define action delete_all_unsigned_cookies
     iterate(request.header.Cookie)
          iterator.prefix= "BCSIG_" iterator.delete()
          request.header.Cookie.regex=!"$(iterator:rewrite(([^=]*)=(.*),BCSIG_$(1)=$(2:concat($(user)):hmac)))" iterator.delete()
     end
end
 
define action sign_all
     iterate(response.header.Set-Cookie)
          iterator.append("$(iterator):rewrite(([^=]*)=([^;]*)(.*),BCSIG_$(1)=$(2:concat($(user)):hmac)$(3))")
     end
end 

Important Note About This Policy

If users do not authenticate against the ProxySG appliance, the user name is blank and the appliance evaluates policy as if the ":concat($(user))" text were omitted. Consider using the policy described in Using the Client Address if users in your deployment do not authenticate against the ProxySG appliance.