Use the MachineKey API to protect values in ASP.NET

本文介绍如何利用ASP.NET的MachineKeyAPI来保护web应用中需要跨请求传递的敏感状态值,通过加密和验证确保数据安全。特别强调了API在不同版本之间的变化及如何利用其内置的Forms认证和ViewState保护机制。最后提供了一个实际应用示例,展示如何在基于cookie的临时数据提供者中应用这一技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Use the MachineKey API to protect values in ASP.NET

JUNE 21, 2012

It’s quite common to need to preserve state across requests in a web application. This is typically in the form of a cookie, query string or hidden form field. Commonly the state that needs to be sent back to the client is sensitive or we want to ensure it’s not been modified by the user. The typical approach to this should be encrypting (protect) and MACing (verify) the value. Writing this sort of crypto code yourself is possible but not ideal. Fortunately in ASP.NET the MachineKey API already provides this functionality. And yes, this is the same as the <machineKey> infrastructure already used to protect Forms authentication and ViewState.

The API is slightly different between 4.0 and 4.5. Here’s the 4.0 usage with some helpers:

string Protect(byte[] data)
{
    if (data == null || data.Length == 0) return null;
    return MachineKey.Encode(data, MachineKeyProtection.All);
}

byte[] Unprotect(string value)
{
    if (String.IsNullOrWhiteSpace(value)) return null;
    return MachineKey.Decode(value, MachineKeyProtection.All);
}

MachineKey.Encode accepts a byte[] to protect and returns a string. The second parameter is an enum that indicates if you want encryption, validation or both. I’d typically suggest both (MachineKeyProtection.All). The returned string can then be used to pass back to the client as a cookie value or a query string value without concern for viewing or tampering. MachineKey.Decode simply reverses the process.

And here’s the 4.5 usage (it supports a slightly more sophisticated usage):

const string MachineKeyPurpose = "MyApp:Username:{0}";
const string Anonymous = "<anonymous>";

string GetMachineKeyPurpose(IPrincipal user)
{
    return String.Format(MachineKeyPurpose,
        user.Identity.IsAuthenticated ? user.Identity.Name : Anonymous);
}

string Protect(byte[] data)
{
    if (data == null || data.Length == 0) return null;
    var purpose = GetMachineKeyPurpose(Thread.CurrentPrincipal);
    var value = MachineKey.Protect(data, purpose);
    return Convert.ToBase64String(value);
}

byte[] Unprotect(string value)
{
    if (String.IsNullOrWhiteSpace(value)) return null;
    var purpose = GetMachineKeyPurpose(Thread.CurrentPrincipal);
    var bytes = Convert.FromBase64String(value);
    return MachineKey.Unprotect(bytes, purpose);
}

In 4.5 the old APIs are deprecated in favor of these new Protect and Unprotect APIs. The new APIs no longer accept the level of protection (they always encrypt and MAC now [which is good]) and instead now accept a new parameter which is called “purpose”. This purpose parameter is intended to act somewhat as a validation mechanism. If we use a value that’s specific to the user (as we do above with the GetMachineKeyPurpose helper) we then are verifying that the value can only be unprotected by the same user. This is a nice addition in 4.5.

In my Cookie-based TempData provider I used this exact technique — I didn’t want to reinvent crypto or introduce new keys, so leveraging the ASP.NET machine key APIs made a lot of sense.

Oh and one caveat: this does not prevent an eavesdropper from intercepting the value and replaying it, so (as usual) SSL is imperative.

Update: Great follow-up reading about the internals of the MachineKey:




Sample:
 public class MachineKeyProtectionProvider : IDataProtectionProvider
    {
        public IDataProtector Create(params string[] purposes)
        {
            return new MachineKeyDataProtector(purposes);
        }
    }


    public class MachineKeyDataProtector : IDataProtector
    {
        private readonly string[] _purposes;


        public MachineKeyDataProtector(string[] purposes)
        {
            _purposes = purposes;
        }


        public byte[] Protect(byte[] userData)
        {
            return MachineKey.Protect(userData, _purposes);
        }


        public byte[] Unprotect(byte[] protectedData)
        {
            return MachineKey.Unprotect(protectedData, _purposes);
        }
    }


//Using code
var provider = new MachineKeyProtectionProvider();
                manager.UserTokenProvider =
                    new Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider<AppUser, int>(provider.Create("ResetPasswordPurpose"));


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值