Use the MachineKey API to protect values in ASP.NET
2015-01-29 10:08
387 查看
Use the MachineKey API to protect values in ASP.NET
JUNE 21, 2012It’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:
Cryptographic
Improvements in ASP.NET 4.5, pt. 1
Cryptographic
Improvements in ASP.NET 4.5, pt. 2
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"));
相关文章推荐
- how to use javascript to control the usercotrol in the asp.net
- 4 ways to send a PDF file to the IE Client in ASP.NET 2.0
- Unhandled exceptions cause ASP.NET-based applications to unexpectedly quit in the .NET Framework 2.0
- Using the Index Server to create Query Page in asp.net
- How to use the System Restore API to save and to restore system data in Visual C++
- It is not possible to run two different versions of ASP.NET in the same IIS process.问题的解决
- The service cannot be activated because it does not support ASP.NET compatibility. ASP.NET compatibility is enabled for this application. Turn off ASP.NET compatibility mode in the web.config or add the AspNetCompatibilityRequirements attribute to the ser
- How to get the Values of Selected Row from a Gridview using ASP.NET
- I learned several ASP.NET's AJAX ability today! It is so interesting and so easy to use AJAX in ASP.NET.
- How to Pop Open an image window that resizes to fit the image in ASP.net 1.x and 2.0 Beta 1
- How to use FtpWebRequest in asp.net
- how to use Form Authentication in ASP.NET.
- How to set the DefaultButton in a Page Based on ASP.NET Master Page
- Use Office Web Components to Load Excel and perform calculations in ASP.NET
- PRB: "Requested Registry Access Is Not Allowed" Error Message When ASP.NET Application Tries to Write New EventSource in the Eve
- How to use AspnetUpload™ in your web application
- How to achive the CRUD in ASP.NET MVC(VS2010)
- It is not possible to run two different versions of ASP.NET in the same IIS process
- [导入]Thow to use the AspnetUpload control 2.1(2)
- Introduction to the ASP.NET Web API