ASP.NET中等安全模式的一些经验分享
程序员文章站
2024-03-08 11:24:58
非通用型的web程序或产品,通常不会和asp.net中等安全模式打交道,因为面对的用户群体会比较固定,或者部署环境是可以由程序提供者决定的。 但在做通用型的web产品的时候...
非通用型的web程序或产品,通常不会和asp.net中等安全模式打交道,因为面对的用户群体会比较固定,或者部署环境是可以由程序提供者决定的。
但在做通用型的web产品的时候,你就要和各种人打交道了,有的站长用的是国外空间,比如godaddy,外国的空间商通常会把asp.net代码执行权限控制在中等安全模式。
而在中等安全模式下,很多我们习以为常的事情都是做不了的。
中等安全模式是什么?
可能很多人都没接触过中等安全模式,我在参与bbsmax项目之前,我也不知道有中等安全模式这么个东西。
简单来说,asp.net提供了一个简单设置代码执行权限的方案,叫做“信任级别”。
它默认提供5种信任级别,分别是:fulltrust、high、medium、low、minimal。
每个信任级别的设置,分别对应于一组代码权限设置。
这个方案,让网站部署者可以通过web.config快速设置网站的托管代码执行权限。
通过对web.config的<system.web>/<trust>节点的level属性值进行设置,就可以将asp.net程序设置到不同的信任级别。
asp.net安装完,所有网站默认都是fulltrust信任级别,也是最高信任级别。
本文说的“中等安全模式”就是对应于medium信任级别。
因为托管代码执行权限模型不是本文讨论的重点,所以我这里只做简单的说明,不深入讨论asp.net安全级别设置的实现原理,实现原理可以参考本文最后给出的几个连接。
中等安全模式会有哪些影响?
以下是我和我的同事在asp.net中等安全模式下曾经遇到过的一些问题:
1. 基于virtualpathprovider的模板机制不能用,因为virtualpathprovider至少需要运行在high模式。
2. buildprovider不能用,意味着你想自己添加自己的语言实现也不能用了,不过大部分项目不会用到这么高级的东西。
3. codedom、emit不能用了,这下惨了,什么ioc、aop,动态注入的高科技玩意儿,全都废了,这些不是基于codedom的就是基于emit的。
4. 通过aspx页面接管文件下载也不行了,response写文件流到客户端需要更高的代码执行权限。
5. 大文件上传也别想了,因为大文件上传万变不离httpworkrequst,获取httpworkrequst的代码需要fulltrust模式。
6. sqlite不能用了,因为中等安全模式下没有非托管代码调用权限,所以除了sqlite外,涉及到非托管代码调用的,也都废掉了。
7. access数据不能用oledb连接了,因为中等安全模式下,oledbclient是不能用的,你只能用odbc数据源。
所以,如果要考虑允许让用户把程序部署到中等安全模式下,那就越早做中等安全模式的兼容性测试越好。
因为很多不能用的东西,都是涉及到基础结构的。
比如,sqlite和access不能用,你的程序如果正巧就只做这两个数据库的版本,咋办?
比如,文件下载不能通过response写文件流的方式,你的程序正巧又是这么做防盗链,咋办?
中等安全模式要求那么苛刻,怎么对付?
只能绕道走了,要不然怎么办?方法还是有的,得不断尝试。
virtualpathprovider不能用,buildprovider也不能用,但是又需要有自己的一套模板语法。那只好在页面访问前生成aspx页面,再做url重写了。
说起来很简单,就一句话。但是这中间我不知道写了多少代码,做了多少次试验,才找到最佳方案。
所以,你的方法还是得你自己找。
以下是判断程序是否运行在中等安全模式的代码:
if (securitymanager.isgranted(new aspnethostingpermission(aspnethostingpermissionlevel.medium)))
{
}
如果有遇到不是必须执行的逻辑,比如获取程序内存占用率或者大文件上传,那就可以先判断下,再决定是否调用。
根据资料显示,把程序集部署到gac中,可以获得fulltrust级别的权限,不过我没有实际试过。
辰 提供的文件下载方案:
protected override void oninit(eventargs e)
{
response.contenttype = "application/octet-stream";
using (filestream stream = file.open(server.mappath("~/test.txt"), filemode.open))
{
binarywriter writer = new binarywriter(response.outputstream);
byte[] buffer = new byte[1024];
int l = 0;
while ((l = stream.read(buffer, 0, buffer.length)) > 0)
{
writer.write(buffer, 0, l);
}
}
}
但在做通用型的web产品的时候,你就要和各种人打交道了,有的站长用的是国外空间,比如godaddy,外国的空间商通常会把asp.net代码执行权限控制在中等安全模式。
而在中等安全模式下,很多我们习以为常的事情都是做不了的。
中等安全模式是什么?
可能很多人都没接触过中等安全模式,我在参与bbsmax项目之前,我也不知道有中等安全模式这么个东西。
简单来说,asp.net提供了一个简单设置代码执行权限的方案,叫做“信任级别”。
它默认提供5种信任级别,分别是:fulltrust、high、medium、low、minimal。
每个信任级别的设置,分别对应于一组代码权限设置。
这个方案,让网站部署者可以通过web.config快速设置网站的托管代码执行权限。
通过对web.config的<system.web>/<trust>节点的level属性值进行设置,就可以将asp.net程序设置到不同的信任级别。
asp.net安装完,所有网站默认都是fulltrust信任级别,也是最高信任级别。
本文说的“中等安全模式”就是对应于medium信任级别。
因为托管代码执行权限模型不是本文讨论的重点,所以我这里只做简单的说明,不深入讨论asp.net安全级别设置的实现原理,实现原理可以参考本文最后给出的几个连接。
中等安全模式会有哪些影响?
以下是我和我的同事在asp.net中等安全模式下曾经遇到过的一些问题:
1. 基于virtualpathprovider的模板机制不能用,因为virtualpathprovider至少需要运行在high模式。
2. buildprovider不能用,意味着你想自己添加自己的语言实现也不能用了,不过大部分项目不会用到这么高级的东西。
3. codedom、emit不能用了,这下惨了,什么ioc、aop,动态注入的高科技玩意儿,全都废了,这些不是基于codedom的就是基于emit的。
4. 通过aspx页面接管文件下载也不行了,response写文件流到客户端需要更高的代码执行权限。
5. 大文件上传也别想了,因为大文件上传万变不离httpworkrequst,获取httpworkrequst的代码需要fulltrust模式。
6. sqlite不能用了,因为中等安全模式下没有非托管代码调用权限,所以除了sqlite外,涉及到非托管代码调用的,也都废掉了。
7. access数据不能用oledb连接了,因为中等安全模式下,oledbclient是不能用的,你只能用odbc数据源。
所以,如果要考虑允许让用户把程序部署到中等安全模式下,那就越早做中等安全模式的兼容性测试越好。
因为很多不能用的东西,都是涉及到基础结构的。
比如,sqlite和access不能用,你的程序如果正巧就只做这两个数据库的版本,咋办?
比如,文件下载不能通过response写文件流的方式,你的程序正巧又是这么做防盗链,咋办?
中等安全模式要求那么苛刻,怎么对付?
只能绕道走了,要不然怎么办?方法还是有的,得不断尝试。
virtualpathprovider不能用,buildprovider也不能用,但是又需要有自己的一套模板语法。那只好在页面访问前生成aspx页面,再做url重写了。
说起来很简单,就一句话。但是这中间我不知道写了多少代码,做了多少次试验,才找到最佳方案。
所以,你的方法还是得你自己找。
以下是判断程序是否运行在中等安全模式的代码:
复制代码 代码如下:
if (securitymanager.isgranted(new aspnethostingpermission(aspnethostingpermissionlevel.medium)))
{
}
如果有遇到不是必须执行的逻辑,比如获取程序内存占用率或者大文件上传,那就可以先判断下,再决定是否调用。
根据资料显示,把程序集部署到gac中,可以获得fulltrust级别的权限,不过我没有实际试过。
附录a
参考链接:
msdn 《how to: use medium trust in asp.net 2.0》
《check code access security permissions granted to your asp.net web application》
附录b
辰 提供的文件下载方案:
复制代码 代码如下:
protected override void oninit(eventargs e)
{
response.contenttype = "application/octet-stream";
using (filestream stream = file.open(server.mappath("~/test.txt"), filemode.open))
{
binarywriter writer = new binarywriter(response.outputstream);
byte[] buffer = new byte[1024];
int l = 0;
while ((l = stream.read(buffer, 0, buffer.length)) > 0)
{
writer.write(buffer, 0, l);
}
}
}
推荐阅读