D:/test(用户网站目录)继承现有属性并增加app_test_user和iis_test_user完全控制的权限并替换子目录。
以后每增加一个网站都以此类推。
但是,至此,system.io还是对c:/windows又读取权限的,(怀疑network servers用户属于users组,但是好多服务都要使用users组来执行的,所以不能把c:/windwos去掉users组的读取权限)但必须知道系统路径,有两种方案解决。
1、 再安装系统的时候使用无人值守安装,更换c:/windows默认安装路径,如更改为c:/testtest(要符合dos的命名规则,不能超过8个字符)。这个是必需的
2、 以下位置具有指派给 IIS_WPG 的权限:
%windir%/help/iishelp/common – 读取
%windir%/IIS Temporary Compressed Files – 列出、读取、写入
%windir%/system32/inetsrv/ASP Compiled Template – 读取
Inetpub/wwwroot(或内容目录)- 读取、执行
此外,IIS_WPG 还具有以下用户权限:
忽略遍历检查(SeChangeNotifyPrivilege)
作为批处理作业登录(SeBatchLogonRight)
从网络访问此计算机(SeNetworkLogonRight)
当然两种方法结合起来算是最安全的方案,一般使用第一种方案已经算是很安全的,毕竟是用一个webshell来猜测8位字符的目录还是需要花费时间的。使用防火墙很容易就能察觉出来,并加以控制。
第二种可能根据所安装软件不同还要相应增加目录的读取权限,详细情况要根据软件来确定。
如果主机用户比较多,这将是一个相当大的劳动量,推荐使用程序来解决问题,下面给出网上不常见的针对iis应用程序池操作的代码和针对iis虚拟目录的操作代码。
操作iis应用程序池
using System;
using System.DirectoryServices;
using System.Reflection;
namespace ADSI1
{
///
/// Small class containing methods to configure IIS.
///
class ConfigIIS
{
///
/// The main entry point for the application.
///
[STAThread]
//主程序入口,可以选择用哪些,我为了方便,全部功能都写上去了。
static void Main(string[] args)
{
string AppPoolName = "MyAppPool";
string newvdir1 = "MyVDir";
DirectoryEntry newvdir = createVDir(newvdir1);
createAppPool(AppPoolName);
AssignAppPool(newvdir, AppPoolName);
ConfigAppPool("Stop",AppPoolName);
}
//创建虚拟目录
static DirectoryEntry createVDir (string vdirname)
{
DirectoryEntry newvdir;
DirectoryEntry root=new DirectoryEntry("IIS://localhost/W3SVC/1/Root");
newvdir=root.Children.Add(vdirname, "IIsWebVirtualDir");
newvdir.Properties["Path"][0]= "c://inetpub//wwwroot";
newvdir.Properties["AccessScript"][0] = true;
newvdir.CommitChanges();
return newvdir;
}
//创建新的应用程序池。
static void createAppPool(string AppPoolName)
{
DirectoryEntry newpool;
DirectoryEntry apppools=new DirectoryEntry("IIS://localhost/W3SVC/AppPools");
newpool=apppools.Children.Add(AppPoolName, "IIsApplicationPool");
newpool.CommitChanges();
}
static void AssignAppPool(DirectoryEntry newvdir, string AppPoolName)
{
object[] param={0, AppPoolName, true};
newvdir.Invoke("Appcreate3", param);
}
//method是管理应用程序池的方法,有三种Start、Stop、Recycle,而AppPoolName是应用程序池名称
static void ConfigAppPool(string method,string AppPoolName)
{
DirectoryEntry appPool = new DirectoryEntry("IIS://localhost/W3SVC/AppPools");
DirectoryEntry findPool = appPool.Children.Find(AppPoolName,IIsApplicationPool");
findPool.Invoke(method,null);
appPool.CommitChanges();
appPool.Close();
}
//应用程序池的列表
static void AppPoolList()
{
DirectoryEntry appPool = new DirectoryEntry("IIS://localhost/W3SVC/AppPools");
foreach(DirectoryEntry a in appPool.Children)
{
Console.WriteLine(a.Name);
}
}
private void VDirToAppPool()
{
DirectroryEntry VD = new DirectoryEntry("IIS://localhost/W3SVC/1/ROOT/ccc");
Console.WriteLine(VD.Properties["AppPoolId"].Value.ToString());
}
}
}
iis6操作的例子
using System;
using System.DirectoryServices;
using System.Collections;
using System.Text.RegularExpressions;
using System.Text;
namespace Wuhy.ToolBox
{
///
public class IISAdminLib
{
#region UserName,Password,HostName的定义
public static string HostName
{
get
{
return hostName;
}
set
{
hostName = value;
}
}
public static string UserName
{
get
{
return userName;
}
set
{
userName = value;
}
}
public static string Password
{
get
{
return password;
}
set
{
if(UserName.Length <= 1)
{
throw new ArgumentException("还没有指定好用户名。请先指定用户名");
}
password = value;
}
}
public static void RemoteConfig(string hostName, string userName, string password)
{
HostName = hostName;
UserName = userName;
Password = password;
}
private static string hostName = "localhost";
private static string userName;
private static string password;
#endregion
#region 根据路径构造Entry的方法
///
/// 根据是否有用户名来判断是否是远程服务器。
/// 然后再构造出不同的DirectoryEntry出来
///
/// DirectoryEntry的路径
///
public static DirectoryEntry GetDirectoryEntry(string entPath)
{
DirectoryEntry ent;
if(UserName == null)
{
ent = new DirectoryEntry(entPath);
}
else
{
// ent = new DirectoryEntry(entPath, HostName+"//"+UserName, Password, AuthenticationTypes.Secure);
ent = new DirectoryEntry(entPath, UserName, Password, AuthenticationTypes.Secure);
}
return ent;
}
#endregion
#region 添加,删除网站的方法
///
/// 创建一个新的网站。根据传过来的信息进行配置
///
/// 存储的是新网站的信息
public static void createNewWebSite(NewWebSiteInfo siteInfo)
{
if(! EnsureNewSiteEnavaible(siteInfo.BindString))
{
throw new DuplicatedWebSiteException("已经有了这样的网站了。" + Environment.NewLine + siteInfo.BindString);
}
string entPath = String.Format("IIS://{0}/w3svc", HostName);
DirectoryEntry rootEntry = GetDirectoryEntry(entPath);
string newSiteNum = GetNewWebSiteID();
DirectoryEntry newSiteEntry = rootEntry.Children.Add(newSiteNum, "IIsWebServer");
newSiteEntry.CommitChanges();
newSiteEntry.Properties["ServerBindings"].Value = siteInfo.BindString;
newSiteEntry.Properties["ServerComment"].Value = siteInfo.CommentOfWebSite;
newSiteEntry.CommitChanges();
DirectoryEntry vdEntry = newSiteEntry.Children.Add("root", "IIsWebVirtualDir");
vdEntry.CommitChanges();
vdEntry.Properties["Path"].Value = siteInfo.WebPath;
vdEntry.CommitChanges();
}
///
/// 删除一个网站。根据网站名称删除。
///
/// 网站名称
public static void deleteWebSiteByName(string siteName)
{
string siteNum = GetWebSiteNum(siteName);
string siteEntPath = String.Format("IIS://{0}/w3svc/{1}", HostName, siteNum);
DirectoryEntry siteEntry = GetDirectoryEntry(siteEntPath);
string rootPath = String.Format("IIS://{0}/w3svc", HostName);
DirectoryEntry rootEntry = GetDirectoryEntry(rootPath);
rootEntry.Children.Remove(siteEntry);
rootEntry.CommitChanges();
}
#endregion
#region Start和Stop网站的方法
public static void StartWebSite(string siteName)
{
string siteNum = GetWebSiteNum(siteName);
string siteEntPath = String.Format("IIS://{0}/w3svc/{1}", HostName, siteNum);
DirectoryEntry siteEntry = GetDirectoryEntry(siteEntPath);
siteEntry.Invoke("Start", new object[] {});
}
public static void StopWebSite(string siteName)
{
string siteNum = GetWebSiteNum(siteName);
string siteEntPath = String.Format("IIS://{0}/w3svc/{1}", HostName, siteNum);
DirectoryEntry siteEntry = GetDirectoryEntry(siteEntPath);
siteEntry.Invoke("Stop", new object[] {});
}
#endregion
#region 确认网站是否相同
///
/// 确定一个新的网站与现有的网站没有相同的。
/// 这样防止将非法的数据存放到IIS里面去
///
/// 网站邦定信息
///
public static bool EnsureNewSiteEnavaible(string bindStr)
{
string entPath = String.Format("IIS://{0}/w3svc", HostName);
DirectoryEntry ent = GetDirectoryEntry(entPath);
foreach(DirectoryEntry child in ent.Children)
{
if(child.SchemaClassName == "IIsWebServer")
{
if(child.Properties["ServerBindings"].Value != null)
{
if(child.Properties["ServerBindings"].Value.ToString() == bindStr)
{
return false;
}
}
}
}
return true;
}
#endregion
#region 获取一个网站编号的方法
///
/// 获取一个网站的编号。根据网站的ServerBindings或者ServerComment来确定网站编号
///
///
///
///
public static string GetWebSiteNum(string siteName)
{
Regex regex = new Regex(siteName);
string tmpStr;
string entPath = String.Format("IIS://{0}/w3svc", HostName);
DirectoryEntry ent = GetDirectoryEntry(entPath);
foreach(DirectoryEntry child in ent.Children)
{
if(child.SchemaClassName == "IIsWebServer")
{
if(child.Properties["ServerBindings"].Value != null)
{
tmpStr = child.Properties["ServerBindings"].Value.ToString();
if(regex.Match(tmpStr).Success)
{
return child.Name;
}
}
if(child.Properties["ServerComment"].Value != null)
{
tmpStr = child.Properties["ServerComment"].Value.ToString();
if(regex.Match(tmpStr).Success)
{
return child.Name;
}
}
}
}
throw new NotFoundWebSiteException("没有找到我们想要的站点" + siteName);
}
#endregion
#region 获取新网站id的方法
///
/// 获取网站系统里面可以使用的最小的ID。
/// 这是因为每个网站都需要有一个唯一的编号,而且这个编号越小越好。
/// 这里面的算法经过了测试是没有问题的。
///
///
public static string GetNewWebSiteID()
{
ArrayList list = new ArrayList();
string tmpStr;
string entPath = String.Format("IIS://{0}/w3svc", HostName);
DirectoryEntry ent = GetDirectoryEntry(entPath);
foreach(DirectoryEntry child in ent.Children)
{
if(child.SchemaClassName == "IIsWebServer")
{
tmpStr = child.Name.ToString();
list.Add(Convert.ToInt32(tmpStr));
}
}
list.Sort();
int i = 1;
foreach(int j in list)
{
if(i == j)
{
i++;
}
}
return i.ToString();
}
#endregion
}
#region 新网站信息结构体
public struct NewWebSiteInfo
{
private string hostIP; // The Hosts IP Address
private string portNum; // The New Web Sites Port.generally is "80"
private string descOfWebSite; // 网站表示。一般为网站的网站名。例如"www.dns.com.cn"
private string commentOfWebSite;// 网站注释。一般也为网站的网站名。
private string webPath; // 网站的主目录。例如"e:/tmp"
public NewWebSiteInfo(string hostIP, string portNum, string descOfWebSite, string commentOfWebSite, string webPath)
{
this.hostIP = hostIP;
this.portNum = portNum;
this.descOfWebSite = descOfWebSite;
this.commentOfWebSite = commentOfWebSite;
this.webPath = webPath;
}
public string BindString
{
get
{
return String.Format("{0}:{1}:{2}", hostIP, portNum, descOfWebSite);
}
}
public string CommentOfWebSite
{
get
{
return commentOfWebSite;
}
}
public string WebPath
{
get
{
return webPath;
}
}
}
#endregion
}
至此,一个相对安全的.net主机就建立起来了,随着.net2.0的发布越来越逼近,希望ms能针对此问题作一个妥善的防范。
我们已经简单的介绍了一下ASP.NET中关于文件IO系统的漏洞的防治方法,这一方法有些繁琐,但是却可以从根本上杜绝一些漏洞,我们讨论的只是很少的一部分,更多的解决放法需要大家共同来探索、学习.
http://netadmin.77169.com/HTML/20050509000623_4.html