关键词搜索

源码搜索 ×
×

Web Api 安全

发布2017-05-24浏览2188次

详情内容

过去,我写过一两个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'");

        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

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!";
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

二、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"));
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

这里写图片描述

参考文章:
Web Api的安全性

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载