WEBAPI Security Using token+ signature to verify __WEBAPI security

Source: Internet
Author: User
Tags httpcontext md5 md5 encryption tojson
Original address: Webapi using token+ signature verification first, not to verify the way

API Query Interface:

Client invocation: http://api.XXX.com/getproduct?id=value1

As above, this way is simple and rough, in the browser directly input "Http://api." Xxx.com/getproduct?id=value1 ", you can get product list information, but this way there will be a very serious security problems, without any verification, you can get to the product list, resulting in product information leakage.
So, how do you validate the caller identity? How to prevent parameters from being tampered with. How to guarantee the uniqueness of the request. How to guarantee the uniqueness of the request to prevent the request from being maliciously attacked.

second, the use of Token+ signature authentication guarantee Request Security

The main principle of token+ signature authentication is: 1. Do a certification service, provide a certified WEBAPI, the user first access it to obtain the corresponding token

2. The user takes the corresponding token and the requested parameter and the signature algorithm provided by the server to compute the signature before accessing the specified API

3. Every time the server receives a request to obtain the corresponding user's token and request parameters, the server side again compute the signature and the client signature comparison, if the verification through the normal access to the appropriate API, validation failure will return specific failure information

The specific code is as follows:

1. The User requests authentication Service GetToken, saves the token in the server-side cache, and returns the corresponding token to the client (this request does not need to carry on the signature authentication)

Public Httpresponsemessage GetToken (string staffid) {resultmsg resultmsg = null;

            int id = 0; Determines whether the parameter is legitimate if (string. IsNullOrEmpty (StaffID) | | (!int.
                TryParse (StaffID, out ID)) {resultmsg = new resultmsg ();
                Resultmsg.statuscode = (int) statuscodeenum.parametererror;
                Resultmsg.info = StatusCodeEnum.ParameterError.GetEnumText ();
                Resultmsg.data = "";
            Return Httpresponseextension.tojson (Jsonconvert.serializeobject (resultmsg)); ///Insert cache Token Token = (Token) HttpRuntime.Cache.Get (ID.
            ToString ()); if (HttpRuntime.Cache.Get ID.
                ToString ()) = = NULL) {token = new token (); Token.
                StaffID = ID; Token.
                Signtoken = Guid.NewGuid (); Token.
                Expiretime = DateTime.Now.AddDays (1); HttpRuntime.Cache.Insert (token. Staffid.tostring (), token, NULL, token.
            Expiretime, TimeSpan.Zero);
            //Return token information resultmsg =new resultmsg ();
            Resultmsg.statuscode = (int) statuscodeenum.success;
            Resultmsg.info = "";

            Resultmsg.data = token;
        Return Httpresponseextension.tojson (Jsonconvert.serializeobject (resultmsg)); }

2. The client invokes the server-side API, which requires signature authentication of the request, and the signature is as follows

(1) Get request: According to the request parameter name, all request parameters are sorted alphabetically: Keyvaluekeyvalue...keyvalue string such as: Arong=1,mrong=2,crong=3 sorted as: arong=1, Crong =3,mrong=2 then the parameter name and the parameter value are spliced to get the argument string: Arong1crong3mrong2.

public static tuple<string,string> getquerystring (dictionary<string, string> parames) {// The first step: to sort the dictionary alphabetically by key idictionary<string, string> sortedparams = new sorteddictionary<string, String&gt
            ;(p arames);

            ienumerator<keyvaluepair<string, string>> dem = Sortedparams.getenumerator ();  Step Two: String all parameter names and values together StringBuilder query = new StringBuilder (""); Signature string StringBuilder querystr = new StringBuilder (""); URL parameter if (parames = null | | parames.

            Count = 0) return to new Tuple<string,string> ("", ""); while (Dem. MoveNext ()) {string key = Dem.
                Current.key; String value = Dem.
                Current.value; if (!string. IsNullOrEmpty (key)) {query. Append (Key).
                    Append (value); Querystr.append ("&"). Append (Key). Append ("=").
       Append (value);         Return to New tuple<string, string> (query). ToString (), querystr.tostring ().
        Substring (1, querystr.length-1)); }
Post request: Serializes the requested parameter object into a JSON format string
Product Product = new Product () {Id = 1, Name = "58.8", Count = ten, Price = +};
 var data=jsonconvert.serializeobject (product);
(2) Add TimeSpan (timestamp) to the request header, Nonce (random number), StaffID (user ID), signature (signature parameter)
         Join header information
            request. Headers.add ("StaffID", staffid.tostring ()); The currently requested user StaffID request
            . Headers.add ("timestamp", timestamp); Timestamp when initiating request (in milliseconds) request
            . Headers.add ("Nonce", nonce); Timestamp when initiating request (in milliseconds) request
            . Headers.add ("signature", Getsignature (Timestamp,nonce,staffid,data)); Digital signature of current request content
(3) Calculate the signature of this request according to the request parameter, get the SIGNSTR signature string with Timespan+nonc+staffid+token+data (request parameter string), then sort and MD5 encrypt the final signature signature string, Add to request header
private static string Getsignature (string timestamp,string nonce,int staffid,string data) {Token toke
            n = null;
            var resultmsg = Getsigntoken (StaffID);
                if (resultmsg!= null) {if (Resultmsg.statuscode = = (int) statuscodeenum.success)
                {token = Resultmsg.result;
                else {throw new Exception (resultMsg.Data.ToString ());
            } else {throw new Exception ("token is null, employee number is:" +staffid);
            var hash = System.Security.Cryptography.MD5.Create (); Mosaic signature data var signstr = TimeStamp +nonce+ StaffID + token.
            Signtoken.tostring () + data; Sorts the characters in a string in ascending order var sortstr = string.
            Concat (Signstr.orderby (c => c));
            var bytes = Encoding.UTF8.GetBytes (SORTSTR);
          Using MD5 encryption  var md5val = hash.computehash (bytes);
            Converts binary to uppercase hexadecimal StringBuilder result = new StringBuilder (); foreach (var c in md5val) {result.
            Append (c.tostring ("X2")); return result. ToString ().
        ToUpper (); }

(4) Webapi receives the corresponding request, takes out the timespan,nonc,staffid,signature data in the request head, according to TimeSpan to judge whether this request is invalid, according to StaffID takes out the corresponding token to judge whether the token is invalid, The corresponding request parameters are taken out according to the request type. The server side then recalculates the request signature in accordance with the same rules, determining whether the signature data in the request header is the same, and if the same is the case, the normal return data, if not the same, the request may be maliciously tampered with, prohibit access to the corresponding data , return the appropriate error message

Use global filters to intercept all API requests for unified processing

public class Apisecurityfilter:actionfilterattribute {public override void OnActionExecuting (System.Web.Htt
            P.controllers.httpactioncontext actioncontext) {resultmsg resultmsg = null;
            var request = Actioncontext.request; string method = Request.
            Method.method; String StaffID = String.Empty, timestamp = string. Empty, nonce = string. Empty, signature = string.
            Empty;

            int id = 0; if (request). Headers.contains ("StaffID")) {StaffID = Httputility.urldecode (Request. Headers.getvalues ("StaffID").
            FirstOrDefault ()); } if (Request. Headers.contains ("timestamp")) {timestamp = Httputility.urldecode (Request. Headers.getvalues ("timestamp").
            FirstOrDefault ()); } if (Request. Headers.contains ("nonce")) {nonce = Httputility.urldecode (Request. Headers.getvalues ("Nonce"). FirstOrDefault ()); } if (Request. Headers.contains ("signature")) {signature = Httputility.urldecode (Request. Headers.getvalues ("signature").
            FirstOrDefault ());
            The//gettoken method does not require signature verification if (ActionContext.ActionDescriptor.ActionName = = "GetToken") {if (string. IsNullOrEmpty (StaffID) | | (!int. TryParse (StaffID, out ID) | | String. IsNullOrEmpty (timestamp) | | String.
                    IsNullOrEmpty (nonce))) {resultmsg = new resultmsg ();
                    Resultmsg.statuscode = (int) statuscodeenum.parametererror;
                    Resultmsg.info = StatusCodeEnum.ParameterError.GetEnumText ();
                    Resultmsg.data = "";
                    Actioncontext.response = Httpresponseextension.tojson (Jsonconvert.serializeobject (RESULTMSG)); Base.
                    OnActionExecuting (Actioncontext);
                Return
       } else         {base.
                    OnActionExecuting (Actioncontext);
                Return }//Determine if the request header contains the following parameter if (string. IsNullOrEmpty (StaffID) | | (!int. TryParse (StaffID, out ID) | | String. IsNullOrEmpty (timestamp) | | String. IsNullOrEmpty (nonce) | | String.
                IsNullOrEmpty (signature))) {resultmsg = new resultmsg ();
                Resultmsg.statuscode = (int) statuscodeenum.parametererror;
                Resultmsg.info = StatusCodeEnum.ParameterError.GetEnumText ();
                Resultmsg.data = "";
                Actioncontext.response = Httpresponseextension.tojson (Jsonconvert.serializeobject (RESULTMSG)); Base.
                OnActionExecuting (Actioncontext);
            Return
            //Determine whether TimeSpan is valid double ts1 = 0; Double ts2 = (datetime.utcnow-new DateTime (1970, 1, 1, 0, 0, 0, 0)).
            TotalMilliseconds; BOOL Timespanvalidate = Double. TRyparse (timestamp, out ts1);
            Double ts = ts2-ts1; BOOL Falg = ts > Int.
            Parse (websettingsconfig.urlexpiretime) * 1000; if (Falg | |
            (!timespanvalidate))
                {resultmsg = new resultmsg ();
                Resultmsg.statuscode = (int) statuscodeenum.urlexpireerror;
                Resultmsg.info = StatusCodeEnum.URLExpireError.GetEnumText ();
                Resultmsg.data = "";
                Actioncontext.response = Httpresponseextension.tojson (Jsonconvert.serializeobject (RESULTMSG)); Base.
                OnActionExecuting (Actioncontext);
            Return }//Determine if Token is valid Token Token = (Token) HttpRuntime.Cache.Get (ID.
            ToString ()); String Signtoken = String.
            Empty; if (HttpRuntime.Cache.Get ID.
                ToString ()) = = null) {resultmsg = new resultmsg ();
                Resultmsg.statuscode = (int) statuscodeenum.tokeninvalid; REsultmsg.info = StatusCodeEnum.TokenInvalid.GetEnumText ();
                Resultmsg.data = "";
                Actioncontext.response = Httpresponseextension.tojson (Jsonconvert.serializeobject (RESULTMSG)); Base.
                OnActionExecuting (Actioncontext);
            Return else {Signtoken = token.
            Signtoken.tostring ();
            ///NameValueCollection form = HttpContext.Current.Request.QueryString According to the request type; String data = String.
            Empty; Switch (method) {case "POST": Stream stream = HttpContext.Current.Request .
                    InputStream; String Responsejson = String.
                    Empty;
                    StreamReader StreamReader = new StreamReader (stream);
                    data = Streamreader.readtoend ();
                Break Case "GET"://First step: Remove all get Parameters IDictionary<string, string> parameters = new dictionary<string, string> (); for (int f = 0; f < form. Count; f++) {string key = form.
                        KEYS[F]; Parameters.
                    ADD (Key, Form[key]); //Step Two: Sort the dictionary alphabetically by key idictionary<string, string> sortedparams = new sort
                    Eddictionary<string, string> (parameters);

                    ienumerator<keyvaluepair<string, string>> dem = Sortedparams.getenumerator ();
                    Step three: String all parameter names and values together StringBuilder query = new StringBuilder (); while (Dem. MoveNext ()) {string key = Dem.
                        Current.key; String value = Dem.
                        Current.value; if (!string. IsNullOrEmpty (key)) {query. Append (Key).
         Append (value);               } data = query.
                    ToString ();
                Break
                    default:resultmsg = new Resultmsg ();
                    Resultmsg.statuscode = (int) statuscodeenum.httpmehtoderror;
                    Resultmsg.info = StatusCodeEnum.HttpMehtodError.GetEnumText ();
                    Resultmsg.data = "";
                    Actioncontext.response = Httpresponseextension.tojson (Jsonconvert.serializeobject (RESULTMSG)); Base.
                    OnActionExecuting (Actioncontext);
            Return
            BOOL result = Signextension.validate (timestamp, nonce, ID, signtoken,data, signature);
                if (!result) {resultmsg = new resultmsg ();
                Resultmsg.statuscode = (int) statuscodeenum.httprequesterror;
                Resultmsg.info = StatusCodeEnum.HttpRequestError.GetEnumText ();
     Resultmsg.data = "";           Actioncontext.response = Httpresponseextension.tojson (Jsonconvert.serializeobject (RESULTMSG)); Base.
                OnActionExecuting (Actioncontext);
            Return } else {base.
            OnActionExecuting (Actioncontext);
            } public override void OnActionExecuted (Httpactionexecutedcontext actionexecutedcontext) { Base.
        OnActionExecuted (ActionExecutedContext); }
    }

Detailed Address: http://www.cnblogs.com/MR-YY/p/5972380.html#!comments








Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.