如果使用文件工作,很有可能要用到文件路径和目录路径。路径信息用普通的字符串保存,它会产生从令人头痛的小麻烦到严重的安全漏洞等一些列问题。
这里可以使用System.IO.Path类,它提供了若干执行常见的路径处理任务的静态辅助方法。例如Path.Combine()方法可以把一个完整的目录路径与那个目录中的任意文件名一起使用,如下所示:
为了防止规范化错误之类的安全风险,可以使用Path类。规范化错误时一种特殊类型的应用程序错误,它会在你的代码假定用户提供的值总是符合标准格式时发生。规范化错误时一项低层的技术,但一旦发生就会非常严重,它们通常会导致用户可以执行某个本应该收到限制的动作。
一个有名的规范化错误时Sql注入,通过用户提交一个格式不正确的值从而欺骗你的应用程序执行被修改的sql命令。其他形式的规范化错误可能发生在路径和url中。
例如,考虑下面的方法,它从一个固定的文档目录返回文件数据:
这段代码看起来很简单,它把用户提供的文件名和路径Document相连接,从而允许用户获得目录中任意文件的数据。问题是文件名可能会以多种格式出现。除了提交一个合法的文件名称外,攻击者可以提供一个有效的文件名,如:..\filename 。连接后的路径 WebApp\Documents\..\filename将会从Document的父目录(WebApp)获取文件。利用相似的方式用户可以指定Web应用程序所在驱动器的任意文件名。因为Web服务仅受ASP.NET 工作进程的限制,所以用户可能会被允许下载敏感的服务端文件。
代码的修复其实很简单。再次借助Path类。这次,应该用GetFileName()方法取得字符串的最终文件名部分:
这样就保证了用户只能访问正确的目录。如果要处理url,可以用System.Url类型实现统一的神奇操作。例如,下面的代码演示了如何从url里移除查询字符串参数以确定它指向给定的服务器和虚拟目录:
虽然Path类有从目录结构向下延展(在路径中加入子目录)的方法,但它没有提供任何返回的方法(从路径中移除子目录)。不过可以在Combine()方法中使用相对路径来打破这一限制,相对路径表示“目录向上移动一层”。此外,还可以对返回的结果调用GetFullPath(),让它以正常的格式返回。
下面是一个例子: