IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]Web Api 安全

    leftfist发表于 2017-05-24 05:25:33
    love 0

    过去,我写过一两个Web Api,没有任何身份校验和安全措施,随便在浏览器中输入地址就能访问,谁都可以。无异于裸奔。

    有关Web Api的安全措施,我目前了解到的有以下一些:

    一、使用Basic Authentication验证用户
    客户端在发送Http请求的时候在Header部分提供一个基于Base64编码的用户名和密码,形式为“username:password”,消息接收者(服务器)进行验证,通过后继续处理请求。

    这里写图片描述

    实现方法:
    1、定义一个安全特性”ApiAuthorizeAttribute”

    using System;
    using System.Net;
    using System.Net.Http;
    using System.Security.Principal;
    using System.Text;
    using System.Threading;
    using System.Web.Http.Filters;
    
    namespace WebApi
    {
        public class ApiAuthorizeAttribute : AuthorizationFilterAttribute
        {
    
            public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
            {
                //forms authentication Case that user is authenticated using forms authentication//so no need to check header for basic authentication.
                if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
                {
                    return;
                }
    
                var authHeader = actionContext.Request.Headers.Authorization;
    
                if (authHeader != null)
                {
                    if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&
                        !String.IsNullOrWhiteSpace(authHeader.Parameter))
                    {
                        var credArray = GetCredentials(authHeader);
                        var userName = credArray[0];
                        var password = credArray[1];
    
                        //if (IsResourceOwner(userName, actionContext))
                        if(isCheckOK(userName,password))
                        {
                            //You can use Websecurity or asp.net memebrship provider to login, for
                            //for he sake of keeping example simple, we used out own login functionality
                            //if (TheRepository.LoginStudent(userName, password))
                            {
                                var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName), null);
                                Thread.CurrentPrincipal = currentPrincipal;
                                return;
                            }
                        }
                    }
                }
    
                HandleUnauthorizedRequest(actionContext);
            }
            private bool isCheckOK(string username,string pwd)
            {//这里我只是简单做个判断;可以引入数据库操作做一般意义上的校验
                return (username == "chenqu");
            }
            private string[] GetCredentials(System.Net.Http.Headers.AuthenticationHeaderValue authHeader)
            {
    
                //Base 64 encoded string
                var rawCred = authHeader.Parameter;
                var encoding = Encoding.GetEncoding("iso-8859-1");
                var cred = encoding.GetString(Convert.FromBase64String(rawCred));
    
                var credArray = cred.Split(':');
    
                return credArray;
            }
    
            private bool IsResourceOwner(string userName, System.Web.Http.Controllers.HttpActionContext actionContext)
            {
                var routeData = actionContext.Request.GetRouteData();
                var resourceUserName = routeData.Values["userName"] as string;
    
                if (resourceUserName == userName)
                {
                    return true;
                }
                return false;
            }
    
            private void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
    
                actionContext.Response.Headers.Add("WWW-Authenticate",
                                                   "Basic Scheme='eLearning' location='http://localhost:8323/account/login'");
    
            }
        }
    }

    2、Web Api的controller或action上应用安全特性”ApiAuthorizeAttribute”

    namespace WebApi.Areas.Test.Controllers
    {
        public class Test1Controller : ApiController
        {
            [ApiAuthorize]
            public string Get(int id)
            {
                return "Hello World! Hello Human!";
            }
        }
    }

    二、https
    由于在Basic Authentication验证用户方式中,用户名和密码仅适用base64编码,因此为了保证安全性,basic authentication通常是基于SSL连接(https)。

    将一个网站设置成支持https协议很简单,以IIS为例:
    这里写图片描述

    这里写图片描述

    这里写图片描述

    一定要绑定一个证书,否则会无法访问。

    另外,https这里绑定的端口是443(默认),那么地址
    https://testweb/webapi/api/test/test1/1 相当于
    https://testweb:443/webapi/api/test/test1/1。
    我有一次因为创建了一个本地网站,端口是8000,然后支持https,思维定式地认为访问地址是:https://testweb:8000/,结果提示404。https可不是单纯地在http后面加个s而已,是两种不同的协议,分别有自己对应的端口。

    有关这个https,证书,服务器端证书,客户端证书,是另外一个主题。

    三、如何访问这些Web Api?
    既然是Web Api,并非是在浏览器地址里输入进行访问的,主要还是在程序里调用。
    以C#为例。客户端:

    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            static readonly Encoding UTF8 = Encoding.GetEncoding("utf-8");
            private void button1_Click(object sender, EventArgs e)
            {
                using (WebClient webClient = new WebClient())
                {
                    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
                    webClient.Encoding = UTF8;
                    webClient.Credentials = new NetworkCredential("chenqu", "123456");
    
    MessageBox.Show(webClient.DownloadString("https://localhost/webapi/api/test/test1/1"));
                }
            }
        }

    这里写图片描述

    参考文章:
    Web Api的安全性



沪ICP备19023445号-2号
友情链接