Python33

编程入门 行业动态 更新时间:2024-10-26 12:31:37
Python33 - 使用BaseHTTPRequestHandler提高服务器安全性(Python33 - Improving server security with BaseHTTPRequestHandler)

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

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

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

此外,如果你想知道我为什么不使用nginx或apache ,我想创建自己的网络服务器和网站用于学习目的。 我不打算自己运行一个真实的网站,如果我愿意,我可能会租用服务器或使用现有的服务器软件。

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)

I have lately been improving security on my webserver, which I wrote myself using http.server and BaseHTTPRequestHandler. I have blocked (403'd) most essential server files, which I do not want users to be able to access. Files include the python server script and all databases, plus some HTML templates.

However, in this post on stackoverflow I read that using open(curdir + sep + self.path) in a do_GET request might potentially make every file on your computer readable. Can someone explain this to me? If the self.path is ip:port/index.html every time, how can someone access files that are above the root / directory?

I understand that the user (obviously) can change the index.html to anything else, but I don't see how they can access directories above root.

Also if you're wondering why I'm not using nginx or apache, I wanted to create my own web server and website for learning purposes. I have no intention to run an actual website myself, and if I do want to, I will probably rent a server or use existing server software.

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)

最满意答案

你做了一个无效的假设:

如果self.path都是ip:port/index.html ,那么有人如何访问root /目录之上的文件?

但是self.path是ip:port/index.html 。 尝试记录它,看看你得到了什么。

例如,如果我请求http://example.com:8080/foo/bar/index.html ,则self.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它。

这可以捕捉其他逃脱监狱的方式以及传递..字符串...但它不会抓住一切。 例如,如果有一个符号链接指向jail,那么abspath就无法判断某人已经通过了符号链接。

You're making an invalid assumption:

If the self.path is ip:port/index.html every time, how can someone access files that are above the root / directory?

But self.path is never ip:port/index.html. Try logging it and see what you get.

For example, if I request http://example.com:8080/foo/bar/index.html, the self.path is not example.com:8080/foo/bar/index.html, but just /foo/bar/index.html. In fact, your code couldn't possibly work otherwise, because curdir+ sep + self.path would give you a path starting with ./example.com:8080/, which won't exist.

And then ask yourself what happens if it's /../../../../../../../etc/passwd.

This is one of many reasons to use os.path instead of string manipulation for paths. For examples, instead of this:

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

Do this:

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

I'm assuming that curdir here is an absolute path, not just from os import curdir or some other thing that's more likely to give you . than anything else. If it's the latter, make sure to abspath it as well.

This can catch other ways of escaping the jail as well as passing in .. strings… but it's not going to catch everything. For example, if there's a symlink pointing out of the jail, there's no way abspath can tell that someone's gone through the symlink.

更多推荐

本文发布于:2023-07-24 00:30:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1239313.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!