清理字符串以防止相对 URI 路径

Posted

技术标签:

【中文标题】清理字符串以防止相对 URI 路径【英文标题】:Sanitizing string to prevent relative URI paths 【发布时间】:2013-04-02 10:04:25 【问题描述】:

我创建了这个 HTTP 处理程序来更新本地 SQL Express 数据库中的信息。

我意识到用户可以使用相对 URI 路径“/../../file.zip”作为查询字符串,并且能够下载限制区域之外的文件。

该网站尚未上线,因此目前不是安全问题,但我真的很想阻止这样的事情发生。

我添加了一个简单的 string.replace 行,用于从输入查询中删除任何“..”。

我还应该在这里做些什么来确保这一点?

public void ProcessRequest(HttpContext context)

    string filesPath = "C:/Downloads/";
    string fileName = context.Request.QueryString["filename"];
    fileName = fileName.Replace("'", "''").Replace("..", "").Replace("/", "").Replace("\\", "");

    if (!string.IsNullOrEmpty(fileName) && File.Exists(filesPath + fileName))
    
        context.Response.ContentType = "application/octet-stream";
        context.Response.AddHeader("Content-Disposition", string.Format("attachment; filename=\"0\"", fileName));
        context.Response.WriteFile(filesPath + fileName);
        //Do work to update SQL database here
    
    else
    
        context.Response.ContentType = "text/plain";
        context.Response.Write(filesPath + fileName + " Invalid filename");
    

【问题讨论】:

一般来说,您应该拒绝无效输入,而不是尝试删除有害序列 - 考虑一下您的替换对 ./. 做了什么。还有一堆导致奇怪的模式,如空文件名、前导和尾随点和空格、控制字符、SHORTN~1.AMEs 和可能的保留文件名(com1 等)。在文件名中使用输入很难正确,especially in Windows - 如果可以(正如 Jason 建议的那样)使用生成的 ID 作为本地磁盘上的文件名,那就更好了。 @bobince 那里有很棒的提示。这就是我问这个问题的原因,因为我知道会有更好的方法来解决这个问题,我只是在像这样的重要问题上寻找一些指导。 【参考方案1】:

我通常用这个简单的代码来检查这个问题:

(我直接输入,可能编译不出来,仅供参考)

private string getPath(string basePath, string fileName)

    var fullPath = System.IO.Path.GetFullPath(System.IO.Path.Combine(basePath, fileName));
    if (fullPath.StartsWith(basePath))
        return fullPath;
    return null;

目标是使用Path.GetFullPath。此方法会将任何 /../ 等转换为完整路径。然后检查返回的路径是否在允许的目录中。 请注意,此方法可能会返回与预期略有不同的路径,请阅读MSDN 了解详细说明

【讨论】:

我喜欢这种方法背后的想法——让系统告诉你它将打开什么文件,并确保它是有效的。如果你试图将文件名中的字符或字符串列入黑名单,你无疑会错过一些东西。 这里也有好主意。这是我最初尝试做的,但我没有找到正确的方法来使用。 GetFullPath 是我没找到的方法。【参考方案2】:

你可以让Request.QueryString["filename"] 实际上是一个代表文件的键。如果您不希望用户能够轻松猜测文件密钥,则密钥可以是数字或随机字符串。您可以将映射存储在数据库中,并使用密钥来检索本地文件名(如果您想让两者不同并真正隐藏您的实现细节,则可能是显示文件名)。

【讨论】:

我认为这是最好的方法,但我标记了@Fabske 答案,因为它回答了我原来的问题。我不知道该怎么做,但我会考虑使用这种方法。

以上是关于清理字符串以防止相对 URI 路径的主要内容,如果未能解决你的问题,请参考以下文章

Java中路径的获取总结以及URL和URI的区别

路径部分中带有 // 的 URL 是不是有效?

Servlet中关于路径的小结

在 Uri 对象上,原始字符串属性可以为空吗?

绝对 URI 中的相对路径:java.net.URI.checkPath(URI.java:1823)

新的 Uri 解码相对路径