由于ASP.NET存在服务器端控件,但是Web又是无状态的,于是就用到了ViewState,将服务器控件状态信息存储到ViewState,通过与服务器交互进行数据的传递。而ViewState其实是存储在hidden中,这样就很容易被非法获取、篡改。
于是今天的引子就出来了,即初步研究下ViewState相关原理机制,然后一定程度解决前文所述问题。
有两篇好文可以先分享出来:
.Net 反序列化之 ViewState 利用 - 安全客,安全资讯平台 (anquanke.com)https://www.anquanke.com/post/id/221630#h2-4ASP.NET 小技巧:重写 ViewState 的存储目的地,以提高页面性能 - 走看看 (zoukankan.com)http://t.zoukankan.com/RChen-p-338327.html我这里从实用角度做一简化,从代码层面、配置方面简单记录下。
代码层面,ViewState主要就涉及2个Page重写方法:
一个是加载ViewState(来源于客户端)LoadPageStateFromPersistenceMedium()
一个是保存ViewState(然后输出到客户端)SavePageStateToPersistenceMedium(object state)
那么,我们为了防篡改,可以对这两个方法进行重写,对保存ViewState进行加密、对加载ViewState解密处理。
保存ViewState进行加密
- ///
- /// 传递到前端执行,进行数据加密
- ///
- ///
- protected override void SavePageStateToPersistenceMedium(object viewState)
- {
- LosFormatter format = new LosFormatter();
- StringWriter writer = new StringWriter();
- //序列化
- format.Serialize(writer, viewState);
-
- string vsRaw = writer.ToString();
- //加密
- string vsText = DESCryptoServiceHelper.Encrypt(vsRaw);
-
- Pair pair;
- PageStatePersister persister = this.PageStatePersister;
- object newViewState;
- if (viewState is Pair)
- {
- pair = (Pair)viewState;
- persister.ControlState = pair.First;
- newViewState = pair.Second;
- }
- else
- {
- newViewState = viewState;
- }
- //重新保存
- persister.ViewState = vsText;
- persister.Save();
- }
加载ViewState解密
- ///
- /// 后台加载的时候调用,需要先解密
- ///
- ///
- protected override object LoadPageStateFromPersistenceMedium()
- {
- PageStatePersister persister = this.PageStatePersister;
- persister.Load();
-
- if (persister != null)
- {
- string viewState = persister.ViewState.ToString();
-
- string vsRaw = DESCryptoServiceHelper.Decrypt(viewState);
-
- LosFormatter formatter = new LosFormatter();
- //解密
- return formatter.Deserialize(vsRaw);
- }
- return null;
- }
Web.Config配置
- <system.web>
- <compilation debug="true" targetFramework="4.0" />
- <pages viewStateEncryptionMode="Always" enableViewStateMac="true">pages>
- system.web>
配置节点pages,第一个属性控制是否加密,第二个控制是否通过Mac地址加密