python - Python CGI 内部错误 login.html login.cgi
问题描述
我目前正在尝试为我在带有 Ubuntu 的虚拟机上运行的实际本地网页创建一个简单的登录页面。
我LoginPage.html
在该位置创建了/var/www/html
。
login.cgi
HTML文件然后调用/usr/lib/cgi-bin/login.cgi
.
我得到一个Internal Server Error
. 日志基本上只显示了这一点:
"POST /cgi-bin/login.cgi HTTP/1.1" 500 799 "http://localhost/LoginPage.html" "Mozialla/5.0 (X11; Ubtuntu; Linux x86_64; rv:84.0) Geck/201000101 Firefox/84.0
HTML 文件似乎按预期工作,但是当我按登录并重定向到 CGI 文件时,我在 CGI 文件上收到错误消息。我试图删除 CGI 文件中的所有内容,只留下几行但仍然出现错误。
我在cgi-bin
文件夹中的其他项目文件仍然可以正常工作。
<HTML>
<HEAD><TITLE>Login Page</TITLE></HEAD>
<BODY>
<CENTER>
<FORM method="POST" action="/cgi-bin/login.cgi">
<paragraph> Enter your login name: <input type="text" name="login">
<paragraph> Enter your password: <input type=password name="password">
<paragraph> <input type="submit" value="Connect">
</FORM>
</CENTER>
<HR>
</form>
</BODY>
</HTML>
#!/usr/bin/python3
import sys
import cgi
import os
import cgitb
sys.path.insert(0,'/usr/lib/project_name')
def header():
#print "Content-type: text/html\n"
print("<HEAD>")
print("<TITLE> title </TITLE>")
print("</HEAD>")
def Log():
print("<!DOCTYPE html>")
print("<HTML>")
print("<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\">")
print(" <meta charset=\"utf-8\" />")
header()
print("BODY")
form = cgi.FieldStorage()
login = "login"
password = "test123"
if not (form):
header("Login Response")
print("<BODY>")
elsif (form.has_key("login") and form["login"].value == login and form.has_key("password") and form["password"].value == password):
header("Connected ...")
print("<BODY>")
print("<center><hr><H3>Welcome back,\" , form[\"login\"].value, \".</H3><hr></center>")
print("r\"\"\"<form><input type=\"hidden\" name=\"session\" value=\"%s\"></form>\"\"\" % (form[\"login\"].value)")
print("<H3><a href=\"/cgi-bin/projects.cgi\">Click here to start browsing</a></H3>")
else:
header("No success!")
print("<BODY>")
print("<H3>Please go back and enter a valid login.</H3>")
def footer():
print("</BODY>")
print("</HTML>")
print("Content-type:text/html\r\n\r\n")
cgitb.enable()
Log()
footer()
编辑:
以下是error.log
解决后的内容Internal Server Error
:
[2021 年 2 月 2 日星期二 08:40:41.199152] [cgi:error] [pid 10292:tid 140490049578752] [client 127.0.0.1:38888] AH01215: (2) 没有这样的文件或目录:'/usr/lib/ 的执行cgi-bin/login.cgi' 失败:/usr/lib/cgi-bin/login.cgi,引用者:http://localhost/LoginPage.html [Tue Feb 02 08:40:41.199411 2021] [cgi:error] [pid 10292:tid 140490049578752] [client 127.0.0.1:38888] 头文件前的脚本输出结束:login.cgi,引用者:http://localhost/LoginPage.html
解决方案
更正设置:
没有这样的文件或目录:'/usr/lib/cgi-bin/login.cgi'的执行失败:/usr/lib/cgi-bin/login.cgi,引用者:http://localhost/LoginPage.html
确保 CGI 脚本及其父目录具有正确的权限:
chmod 755 /usr/lib/cgi-bin/ /usr/lib/cgi-bin/login.cgi
此外,CGI 脚本似乎可能有 windows 行尾,因此请确保您也删除了这些行尾,例如通过运行dos2unix login.cgi
(有关更多详细信息,请参阅这篇文章)。
解决内部服务器错误:
首先,至少进行以下更改以更正您的语法(这是导致 的原因Internal Server Error
):
elsif
应该elif
- 你的
header
函数应该接受一个参数,即def header(title)
- 在你拥有的地方
form.has_key
,将其更改为使用,in
因为has_key
现在已弃用,例如,"password" in form
而不是form.has_key("password")
更正后的情况如下所示:
elif "login" in form and form["login"].value == login and "password" in form and form["password"].value == password:
顺便说一句,坚持使用所有最新浏览器都支持的HTML5,并且该center
标签现在已被弃用(它已不再是该marquee
标签的方式)。改用 CSS。
此外,作为一个完整的旁注,这些天来,很少看到所有大写字母用于 HTML 标记。您在某些地方使用了该样式,但我建议放弃它以支持小写标记名称。
简化 HTML 生成:
除了上述之外,我建议使用f-strings进行字符串格式化,还建议使用多行字符串来简化逻辑。
下面是一些如何增强代码的示例。
您的标题函数可能看起来像这样使用 f-strings 和多行字符串,如建议的那样。title
参数是可选的。
def header(title=""):
print(f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> {title} </title>
</head>
<body>
""")
您的页脚功能可能如下所示:
def footer():
print("""
</body>
</html>
""")
最后,您的 HTML 表单可能如下所示,text-align: center;
用于居中:
print(f"""
<hr>
<h3 style="text-align: center;">Welcome back { form["login"].value }</h3>
<hr>
<form>
<input type="hidden" name="session" value="{ form["login"].value }">
</form>
<h3>
<a href="/cgi-bin/projects.cgi">Click here to start browsing</a>
</h3>
""")
美化 HTML:
为了进一步美化 HTML,您可以import textwrap
然后使用textwrap.dedent()
从 HTML 中删除常见的前导空格(由于 Python 中的缩进),例如
print(textwrap.dedent(f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> {title} </title>
</head>
<body>
"""))
这有两个好处:
- 它在通过网络发送之前删除了不必要的前导空格 - 因此您发送的数据更少,节省带宽
- 当您使用客户端浏览器检查 HTML 源代码时,它会更漂亮——对调试很有用
或者,使用 HTML 模板:
进一步的增强是利用 HTML 模板框架,例如Jinja2。这将允许您将 HTML 存储到文件中,然后通过传递变量来呈现 HTML 文件。
然后,您的 Python 代码会变得简单得多。您只需渲染模板并传递您想要的变量。例如,对于您的标题,它可能是这样的:
template = env.get_template('header.html')
print(template.render(title='Connected ...'))
您需要先设置Environment
这样的:
from jinja2 import Environment
env = Environment(
loader=PackageLoader('package', 'templates')
autoescape=select_autoescape(['html'])
)
并将您的header.html
文件放在一个名为templates
.
您可能还想了解关注点分离原则和MVC 架构。使用这样的模板只是接近实现 MVC 的一步。
关于安全性的最后一点:
看起来您正在使用 HTMLhidden
字段来存储用户名,并将其视为会话令牌。这是非常不安全的,并且不会扩展。不过,它可能足以满足您的目的。Set-cookie
改进它的一种简单方法是使用标头将其存储为 cookie并制作它HttpOnly
,例如
Set-cookie: session=value; HttpOnly
哪里value
可能是一些独特的令牌(例如 a uuid
)。
这比您当前的方法要好得多。
但是,更好的是,您可以使用类似的库来实现安全性PyJWT
。