Web Api安全性设计

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Fanbin168/article/details/51008483


分布式通讯框架-->一个系统要访问另外一个系统中的数据,有一下三种方法,第一种分为2种


1.0 ,MVC Webapi  (严格的讲它其实仅仅是一个设计方案,而不是一个设计框架,Webapi流行的标准RESTfu) (也需要做安全性设计)


1.1 , 自己写一个.ashx一般处理程序 (它其实就是提供一个url供别人调用,这个url返回一个xml或者一个Json格式的数据,但是这需要注意安全性设计
 为什么需要做安全性设计呢?那是因为你现在提供一个url供别人调用(提供数据)但是你这个url并不是向所有人都开放的,我只对指定的客户进行开放,
 例如指定的用户只要按照协议的url向我提供的这个url请求,我就给它数据,
 比如用户请求  http://api.taobao.com/getorderinfo/?uid=123&pric=1000&......  (这种是RESTfu标准的URL格式)
 或者用户请求 http://api.taobao.com/getorde.ashx?uid=123&pric=1000&.... (非标准RESTfu的URL格式) 
 而这个URL是暴露的。谁拿到这个url都可以向我的服务器请求获取数据。那么这就不安全。所有需要做安全设计。
 
 那我们如何来做这个加密呢?
 答案很简单:例如客户端下订单为例:
 1.0首先api这个服务端要分配一些uid给客户端,客户端向服务器请求的时候带上这个ui参数,服务器就根据这个uid去数据库中查询是否有这个uid,如果有则可以初始的表明这个客户端是我的合作客户,这仅仅是第一步
 
 2.0 客户端下单,首先要告诉服务器 下单的数量,价格 等等。到时候这些业务参数也需要随着url带给服务器
 
 3.0 因为url始终是暴露在外面的,即便你带了这么多参数,非法分子拿到你的url,照样也可以像我服务器发送请求。那怎么办法呢? 方法很简单,就是给url的参数再加一个签名sign
 这个签名怎么做的呢?
 服务端在和客户端签订合同的时候,说:现在你的我的合法客户,我分配一个uid和一个密码给你,将来你来请求我服务端的时候带上的签名参数用我的这个密码进行加密。

(其实就是在业务参数相加后再加一个服务器给你一个密码,然后对这个新的字符串进行MD5加密,然后给这个加密后的字符串赋值给sign,也随着url传递到服务端。然后服务器收到这些参数后,再在服务器端对这些业务参数相加,然后在加上这个和客户端约定的密码,看与客户端相加起来并进行MD5加密后的字符串与客户端传递过来的sign值是否一致,如果一致,就参数没有被篡改,否则就是篡改了)
 
 首先服务器端就是将各个参数相加 例如客户端的id是123,下单的价格是35元,下单的数量是2份 
 假设服务器分配了一个abc的密码给客户端,客户端拿到这个密码后将参数再加上在这密码 于是就组成了
 这样 '123'+'35'+'2'+abc='123352abc' (一般是字符串的形式相加)


 做到以上步骤还不行,以上仅仅是解决了非法分子拿到url后最参数进行篡改的问题,但是有一些非法分子拿到了你加了签名的url,不改动,利用这个原url地址可以不断的向我服务端发起请求,
 这样我们就需要将这个url添加一个过期时间。这样,即便非法分子拿到这个url,再向我服务器发送请求,服务器收到请求后提取客户端带过来的那个请求时间,再获取下当前时间,如过大于10秒钟,就说明url就过期了。所以就不能在请求了。那么如何做呢?
 答案非常简单,仅仅只需要给url参数加一个时间就可以了。(一般是加时间戳,这里我们简单点,加一个当前时间也是可以)
 所以:各个参数以字符串的形式相加就变成了:'123'+'35'+'2'+abc+'2016/3/29 18:45:50'='123352abc2016/3/2918:45:50'


 然后对这个参数进行MD5加密,然后把这个密文赋给sign 然后以参数的形式通过url传递到服务端。
 最后这个客户端请求的url为:
 http://api.taobao.com/setorder.ashx?uid=123&pric=35&number=2&time=123352abc2016/3/2918:45:50&sign=3c8c1dc9b592225251a0fe799d68bcfa
 
 ) 


2 , WebService


3 , WCF


新建一个ASP.NET Web应用程序的,添加一个SetOrder.ashx的一般处理程序,作为一个手写的Web Api ,这个API返回一个Json格式的字符串


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Web.WebApi
{
    /// <summary>
    /// SetOrder 的摘要说明
    /// </summary>
    public class SetOrder : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            //这是一个演示客户下单的Demo; 服务端返回一个json数据给客户端{state:0,msg=下单成功}

            //验证参数是否篡改
            string uid = context.Request["uid"];
            string price = context.Request["price"];
            string number = context.Request["number"];
            string time = context.Request["time"];
            string sign = context.Request["sign"];

            //之前和客户端约定,在url的各个参数用字符串的形式相加后再在后面添加一个abc的密码,然后用MD5对这个字符串进行加密赋给sign,传递过来。

            //根据uid去数据库中获取加密的密码(即:获取那个abc)
            //将接收到的参数按照和客户端约定的顺序进行拼接成字符串(支付宝)
            string paramStr = uid + price + number + time + "abc";

            //对这个字符串进行MD5加密
            string md5Sign = MD5Entity(paramStr);


            //如果客户端传入的sign与服务器重写加密以后的前面不相等,那么就说明这个url一个非法的请求
            if (string.Equals(sign, md5Sign, StringComparison.OrdinalIgnoreCase) == false)
            {
                //下单失败()
                context.Response.Write("{state:0,msg:参数有篡改}");
                return;
            };

            //将当客户端传递过来的时间字符串转换成DateTime格式。然后与服务器获取的当前时间比对,如果大于10秒,表示url过期了
            DateTime clientTime = DateTime.Parse(time);

            //将服务器的获取到的当前时间减去客户端请求的时候传递过来的时间
            double timespan = (DateTime.Now - clientTime).TotalSeconds;

            if (timespan > 10 || timespan < 0)
            {
                context.Response.Write("{state:0,msg=url已经过期}");
                return;
            }

            //下单成功
            context.Response.Write("{state:1,msg:请求成功}");

        }

        public string MD5Entity(string str)
        {
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "md5");
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

然后创建一个MVC或者其他应用程序。作为客户端。

比如我这里就有一个MVC的应用程序作为客户端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;

namespace MVC.WebApi.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            string urlFormat = "http://localhost:19078/setorder.ashx?uid={0}&price={1}&number={2}&time={3}&sign={4}";

            string uid = "123";
            string price = "35";
            string number = "2";
            string time = DateTime.Now.ToString("yy-MM-dd HH:mm:ss");

            string signStr = uid + price + number + time + "abc"; //abc是服务器端和客户端约定好的,用于给参数加密的
            string md5Sign = MD5Entity(signStr);

            string url = string.Format(urlFormat, uid, price, number, time, md5Sign);

            //1.0使用C#代码模拟浏览器进行URL的请求得到响应数据 
            WebRequest wRequest = WebRequest.Create(url);

            //设置请求方式为Get请求
            wRequest.Method = "Get";

            //2.0将请求报文发送给服务器,同时拿到服务器的响应报文 
            WebResponse wResponse = wRequest.GetResponse();

            //3.0提取服务器响应报文中的数据(服务端返回的数据是以流的形式返回的)  
            System.IO.Stream stream = wResponse.GetResponseStream();

            string getResponseStr = string.Empty;
            using (System.IO.StreamReader sr = new System.IO.StreamReader(stream))
            {
                 getResponseStr = sr.ReadToEnd();
            }


            return View();
        }

        string MD5Entity(string str)
        {
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "md5");
        }
    }
}


展开阅读全文

没有更多推荐了,返回首页