1

我最近一直在提高我的网络服务器的安全性,我自己使用http.serverBaseHTTPRequestHandler. 我已阻止 ( 403'd) 最重要的服务器文件,我不希望用户能够访问这些文件。文件包括 python 服务器脚本和所有数据库,以及一些 HTML 模板。

但是,在关于 stackoverflow 的这篇文章中,我读到open(curdir + sep + self.path)在 do_GET 请求中使用可能会使您计算机上的每个文件都可读。谁可以给我解释一下这个?如果每次都是,那么有人如何访问根目录上方的self.path文件?ip:port/index.html/

我知道用户(显然)可以将 更改index.html为其他任何内容,但我看不到他们如何访问上面的目录root

另外,如果您想知道我为什么不使用nginxor apache,我想创建自己的 Web 服务器和网站以用于学习目的。我无意自己运行一个实际的网站,如果我愿意,我可能会租用服务器或使用现有的服务器软件。

class Handler(http.server.BaseHTTPRequestHandler):

    def do_GET(self):

        try:
            if "SOME BLOCKED FILE OR DIRECTORY" in self.path:
                self.send_error(403, "FORBIDDEN")
                return
            #I have about 6 more of these 403 parts, but I left them out for readability
            if self.path.endswith(".html"):
                if self.path.endswith("index.html"):
                    #template is the Template Engine that I created to create dynamic HTML content
                    parser = template.TemplateEngine()
                    content = parser.get_content("index", False, "None", False)
                    self.send_response(200)
                    self.send_header("Content-type", "text/html")
                    self.end_headers()
                    self.wfile.write(content.encode("utf-8"))
                    return
                elif self.path.endswith("auth.html"):
                    parser = template.TemplateEngine()
                    content = parser.get_content("auth", False, "None", False)
                    self.send_response(200)
                    self.send_header("Content-type", "text/html")
                    self.end_headers()
                    self.wfile.write(content.encode("utf-8"))
                    return
                elif self.path.endswith("about.html"):
                    parser = template.TemplateEngine()
                    content = parser.get_content("about", False, "None", False)
                    self.send_response(200)
                    self.send_header("Content-type", "text/html")
                    self.end_headers()
                    self.wfile.write(content.encode("utf-8"))
                    return
                else:
                    try:
                        f = open(curdir + sep + self.path, "rb")
                        self.send_response(200)
                        self.send_header("Content-type", "text/html")
                        self.end_headers()
                        self.wfile.write((f.read()))
                        f.close()
                        return
                    except IOError as e:
                        self.send_response(404)
                        self.send_header("Content-type", "text/html")
                        self.end_headers()
                        return
            else:
                if self.path.endswith(".css"):
                    h1 = "Content-type" 
                    h2 = "text/css"
                elif self.path.endswith(".gif"):
                    h1 = "Content-type"
                    h2 = "gif"
                elif self.path.endswith(".jpg"):
                    h1 = "Content-type"
                    h2 = "jpg"
                elif self.path.endswith(".png"):
                    h1 = "Content-type"
                    h2 = "png"
                elif self.path.endswith(".ico"):
                    h1 = "Content-type"
                    h2 = "ico"
                elif self.path.endswith(".py"):
                    h1 = "Content-type"
                    h2 = "text/py"
                elif self.path.endswith(".js"):
                    h1 = "Content-type"
                    h2 = "application/javascript"
                else:
                    h1 = "Content-type"
                    h2 = "text"
                f = open(curdir+ sep + self.path, "rb")
                self.send_response(200)
                self.send_header(h1, h2)
                self.end_headers()
                self.wfile.write(f.read())
                f.close()
                return
        except IOError:
            if "html_form_action.asp" in self.path:
                pass
            else:
                self.send_error(404, "File not found: %s" % self.path)
        except Exception as e:
            self.send_error(500)
            print("Unknown exception in do_GET: %s" % e)
4

2 回答 2

3

你在做一个无效的假设:

如果每次都是,那么有人如何访问根 / 目录上方的文件self.pathip:port/index.html

从来self.path没有。尝试记录它,看看你得到了什么。 ip:port/index.html

例如,如果我请求http://example.com:8080/foo/bar/index.htmlself.path则不是example.com:8080/foo/bar/index.html,而只是/foo/bar/index.html。实际上,您的代码不可能以其他方式工作,因为curdir+ sep + self.path会给您一个以 开头的路径./example.com:8080/,而该路径将不存在。

然后问问自己,如果是/../../../../../../../etc/passwd.

这是使用os.path路径而不是字符串操作的众多原因之一。例如,而不是这个:

f = open(curdir + sep + self.path, "rb")

做这个:

path = os.path.abspath(os.path.join(curdir, self.path))
if os.path.commonprefix((path, curdir)) != curdir:
    # illegal!

我假设这curdir是一条绝对路径,而不仅仅是from os import curdir或其他一些比其他任何东西更有可能给你.的东西。如果是后者,请确保abspath它也是如此。

这可以捕获其他逃离监狱的方式以及传递..字符串……但它不会捕获所有内容。例如,如果有指向监狱的符号链接,则abspath无法判断有人通过了符号链接。

于 2013-08-02T01:42:37.517 回答
2

self.path包含请求路径。如果我要发送GET请求并请求位于 的资源/../../../../../../../etc/passwd,我会跳出您的应用程序的当前文件夹并能够访问您文件系统上的任何文件(您有权读取)。

于 2013-08-02T01:28:40.263 回答