Web Service Security: A Way to Prevent Replay Attacks

This article is intended to bring awareness to the .NET Web service developers about the replay attacks and to learn about measures to secure the Web services they build. The sample source code provided is a nonce, token-based approach to prevent a replay attack. The example is a simple Asp.net web service that will be invoked through a JQuery AJAX call.

Web Service Replay Attacks

Securing a Web service is as important as building one. A Web service exposed over HTTP can be vulnerable in many ways. The most common attack, and the easy one, is the replay attack. A replay attack is a situation where an attacker gets hold of the Web service request along with the valid input parameters and performs repeated hits, either manually or in an automated fashion.

A Web service vulnerable to replay attacks may lead to any of the following worst cases:

  • Hikes up the server memory: In case of data intensive operations
  • Pollutes the data store: In case the Web method does the insertion to the data store
  • Attacker able to manipulate the input parameters and get back the response that might be confidential

Solution: A Nonce Token

A nonce token is a simply cryptographic combination of a unique GUID value and a timestamp. The nonce token should be valid for only one request; also, the timestamp value added to the token can be used to limit the time within which the token is valid. With the use of the GUID value in the nonce token and the timestamp, it will always be unique for each and every request. The original GUID value against which the token can be validated can be shared with the Web service in terms of request header, shared cache/session, cookies, and so forth.

Attack Proof (Replay) Web Service Calls: An Example

In this section, let us create a sample Web service implementing a nonce token validation that will be invoked through jquery AJAX from the page hosted on the same Web site.

Create a Web page named Default.aspx and a WCF service called DataService. In the default.aspx page, populate the nonce token on every page load and pass the same token as a parameter to the WCF method call from the client.

      protected void Page_Load(object sender, EventArgs e)
      {
         PopulateNonce();
      }

      private void PopulateNonce()
      {
         string guid = Guid.NewGuid().ToString();
         // Add the guid to the cookie
         Response.Cookies.Add(new HttpCookie("token")
         // TODO Encrypt and add the value to cookie
         {
            Value = guid
         });
         string plainToken = String.Format("{0}:{1}",
            guid, DateTime.UtcNow);
         // Use a strong and recommended encryption algorithm.
         // Assigning it as it is to make the code simple
         string encryptedToken = plainToken;   // TODO encryption
         hdnNonceToken.Value = encryptedToken;
      }
   }

<asp:Content runat="server" ID="FeaturedContent"
      ContentPlaceHolderID="FeaturedContent">
   <script type="text/javascript">
      $(document).ready(function () {
         $("#btnInvokeWebService").click(function () {
            $.ajax({
               type: "post",
               url: "/Webservices/SecureWebservice/
                  DataService.svc/AddData",
               data: { toke: $("hdnNonceToken").val() },
               contentType: "json",
               success: function () {
               },
               error: function () {
               }
            });
         });
      });
   </script>
</asp:Content>
<asp:Content runat="server" ID="BodyContent"
      ContentPlaceHolderID="MainContent">
   <input type="hidden" id="hdnNonceToken"
      runat="server" />
   <input type="button" id="btnInvokeWebService"
      value="Call the webservice"/>
</asp:Content>

On the Web service side, write the validation logic to validate the given token to ensure that it is not a replay request and the request is made within the expected time threshold. For simplicity, I have not implemented encryption over the nonce token, but in the real world you should encrypt the token with a strong cryptographic algorithm.

      [OperationContract]
      public void AddData(string token)
      {
         if (!IsValidToken(token))
            return;

         // Proceed with the data operation

         return;
      }

      private bool IsValidToken(string token)
      {
         string decryptedToken = token;   //TODO decrypt
          // TODO Decrypt from the cookie
         string guid =
            HttpContext.Current.Request.Cookies["token"].Value;

         string[] array = decryptedToken.Split(new char[] { ':' },
            StringSplitOptions.RemoveEmptyEntries);
         DateTime requestTimestamp = Convert.ToDateTime(array[1]);

         if (array[0].Equals(guid, StringComparison.OrdinalIgnoreCase)
               && (DateTime.UtcNow - requestTimestamp).TotalMinutes <= 5)
            return true;

         return false;
      }

Hopefully, this article has shed light on the replay attack vulnerability and has given you a proven solution to mitigate it.

Happy reading!

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read