Dee*_*101 23 c# ssl https client-certificates asp.net-web-api
为未来的读者编辑:不幸的是,获得赏金的答案不起作用; 我现在无能为力.但是请在下面阅读我自己的答案(通过测试) - 确认可以使用最少的代码更改
我们有一个完全在ASP.NET WebAPI 2.2中的Azure云服务(WebRole)(没有MVC,前端是Angular).我们的一些控制器/ REST端点通过SSL(客户端证书身份验证/相互身份验证)与第三方云服务通信,其余控制器/端点与HTML5/AngularJS前端通信,也通过SSL(但更传统的服务器身份验证) SSL).我们没有任何非SSL端点.我们通过云服务启动任务启用了客户端SSL,例如:
IF NOT DEFINED APPCMD SET APPCMD=%SystemRoot%\system32\inetsrv\AppCmd.exe
%APPCMD% unlock config /section:system.webServer/security/access
Run Code Online (Sandbox Code Playgroud)
问题:该设置是站点范围的,所以即使用户点击第一页(比如https://domain.com,返回angular.html的index.html),他们的浏览器也要求他们提供客户端SSL证书.(下图)
如果有办法要么
要么
我们的服务器的web.config很复杂,但相关的代码片段如下:
<system.webServer>
<security>
<access sslFlags="SslNegotiateCert" />
</security>
</system.webServer>
Run Code Online (Sandbox Code Playgroud)
并且客户端的屏幕截图访问常规WebAPI端点但仍在尝试客户端SSL身份验证(在任何浏览器,Chrome,Firefox或IE中都会发生)

Dee*_*101 15
不幸的是,cleftheris给予奖励的答案不起作用.它试图在HTTP服务器管道/处理中工作太晚以获得客户端证书,但这篇文章给了我一些想法.
该解决方案基于web.config调用"目录"的特殊处理(也适用于虚拟文件夹或WebAPI路由).
这是所需的逻辑:
https://www.server.com/acmeapi/**=> SSL与客户证书
https://www.server.com/**=> SSL
这是相应的配置
<configuration>
...
<system.webServer>
<!-- This is for the rest of the site -->
<security>
<access sslFlags="Ssl" />
</security>
</system.webServer>
<!--This is for the 3rd party API endpoint-->
<location path="acmeapi">
<system.webServer>
<security>
<access sslFlags="SslNegotiateCert"/>
</security>
</system.webServer>
</location>
...
</configuration>
Run Code Online (Sandbox Code Playgroud)
奖励积分
以上将相应地设置SSL握手.现在,您仍然需要在代码中检查客户端SSL证书(如果它是您期望的那个).这样做如下
控制器代码:
[RoutePrefix("acmeapi")]
[SslClientCertActionFilter] // <== key part!
public class AcmeProviderController : ApiController
{
[HttpGet]
[Route("{userId}")]
public async Task<OutputDto> GetInfo(Guid userId)
{
// do work ...
}
}
Run Code Online (Sandbox Code Playgroud)
上面执行SSL客户端验证的实际属性如下.可用于装饰整个控制器或只是特定的方法.
public class SslClientCertActionFilterAttribute : ActionFilterAttribute
{
public List<string> AllowedThumbprints = new List<string>()
{
// Replace with the thumbprints the 3rd party
// server will be presenting. You can make checks
// more elaborate but always have thumbprint checking ...
"0011223344556677889900112233445566778899",
"1122334455667788990011223344556677889900"
};
public override void OnActionExecuting(HttpActionContext actionContext)
{
var request = actionContext.Request;
if (!AuthorizeRequest(request))
{
throw new HttpResponseException(HttpStatusCode.Forbidden);
}
}
private bool AuthorizeRequest(HttpRequestMessage request)
{
if (request==null)
throw new ArgumentNullException("request");
var clientCertificate = request.GetClientCertificate();
if (clientCertificate == null || AllowedThumbprints == null || AllowedThumbprints.Count < 1)
{
return false;
}
foreach (var thumbprint in AllowedThumbprints)
{
if (clientCertificate.Thumbprint != null && clientCertificate.Thumbprint.Equals(thumbprint, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
cle*_*ris 11
您可以在web.config级别上简单地允许纯HTTP流量,并在Web Api管道中为此编写自定义委托处理程序.您可以在此处和此处找到客户端证书委派处理程序.然后,你可以把这个处理活动的"每路由"就像这个例子中发现在这里:
这就是您的路线配置的样子.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "Route1",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "Route2",
routeTemplate: "api2/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: null,
handler: new CustomCertificateMessageHandler() // per-route message handler
);
config.MessageHandlers.Add(new SomeOtherMessageHandler()); // global message handler
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您需要"per-route"委派处理程序,则不得将它们放在全局消息处理程序列表中.
| 归档时间: |
|
| 查看次数: |
8096 次 |
| 最近记录: |