Python CGI 内部错误 login.html login.cgi

Python CGI internal error login.html login.cgi

我目前正尝试在 Ubuntu.

的虚拟机上创建一个简单的登录页面到我 运行 的实际本地网页

我在 /var/www/html 位置创建了 LoginPage.html

HTML 文件然后调用 /usr/lib/cgi-bin/login.cgi 中的 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()

编辑:

这里是解析Internal Server Errorerror.log的内容:

[Tue Feb 02 08:40:41.199152 2021] [cgi:error] [pid 10292:tid 140490049578752] [client 127.0.0.1:38888] AH01215: (2)No such file or directory: exec of '/usr/lib/cgi-bin/login.cgi' failed: /usr/lib/cgi-bin/login.cgi, referer: http://localhost/LoginPage.html [Tue Feb 02 08:40:41.199411 2021] [cgi:error] [pid 10292:tid 140490049578752] [client 127.0.0.1:38888] End of script output before headers: login.cgi, referer: http://localhost/LoginPage.html

更正设置:

No such file or directory: exec of '/usr/lib/cgi-bin/login.cgi' failed: /usr/lib/cgi-bin/login.cgi, referer: http://localhost/LoginPage.html

确保 CGI 脚本及其 parent 目录具有正确的权限:

chmod 755 /usr/lib/cgi-bin/ /usr/lib/cgi-bin/login.cgi

此外,似乎 CGI 脚本可能有 windows 行结尾,因此请确保您也删除它们,例如通过 运行 dos2unix login.cgi(有关详细信息,请参阅 this post)。

正在解决内部服务器错误:

首先,至少进行以下更改以更正您的语法(这是导致 Internal Server Error 的原因):

  1. elsif 应该是 elif
  2. 你的 header 函数应该接受一个参数,即 def header(title)
  3. 在您有 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, which is supported by all the latest browsers, and the center tag is now deprecated (its gone the way of the marquee tag). Use CSS instead

此外,作为一个完整的旁注,如今,ALL CAPS 用于 HTML 标签并不常见。你在某些地方使用过那种风格,但我 suggest dropping it in favor of lowercase tag names.

简化 HTML 代:

除了上述之外,我建议使用f-strings for string formatting and also multi-line strings来简化逻辑。

下面是一些如何增强代码的示例。

您的 header 函数可能看起来像这样使用建议的 f-strings 和 multi-line 字符串。 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 and then use textwrap.dedent() 删除 HTML 中常见的前导空格(由于 Python 中的缩进),例如

print(textwrap.dedent(f"""
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title> {title} </title>
    </head>
    <body>
"""))

这有两个好处:

  1. 它在通过网络发送之前删除了不必要的前导空格——因此您发送的数据更少,节省了带宽
  2. 当您使用客户端浏览器检查时,HTML 源代码更漂亮 -- 对调试很有用

或者,使用 HTML 模板:

进一步的改进是使用 HTML 模板框架,例如 Jinja2。这将允许您将 HTML 存储到文件中,然后通过传递变量来呈现 HTML 文件。

那么,你的Python代码就会变得简单很多。您只需渲染模板并传递所需的变量。比如你header,可能是这样的:

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.

的目录中

您可能还想阅读有关 seperation of concerns principle and the MVC architecture 的内容。使用这样的模板只是离实现 MVC 更近了一步。

关于安全的最后一点:

您似乎在使用 HTML hidden 字段来存储用户名,并将其视为 session 标记。这是 highly insecure and won't scale. Though, it may be sufficient for your purposes. A simple way to improve on it is to store it as a cookie using the Set-cookie header, and make it HttpOnly,例如

Set-cookie: session=value; HttpOnly

其中 value 可能是一些独特的标记(例如 uuid)。

这比您当前的方法要好得多。

但是,更好的是,您可以改用 PyJWT 这样的库来实现安全性。