Section 59.1: 请求方法: GET

通过 GET 调用 CGI 脚本非常简单。

首先,您需要脚本的编码 url。

然后在变量后面加上问号 ?

  • 每个变量都应该有两个部分,中间用 = 分隔。

第一部分应该是每个变量的唯一名称、而第二部分只包含值

  • 变量之间用 & 分隔

  • 字符串总长度不得超过 255 个字符

  • 名称和值需要使用 html 编码(替换: </ , / ? : @ & = + $ )

提示:

使用 html 表单时,请求方法可自行生成。

使用 Ajax 时,可以通过 encodeURI 和 encodeURIComponent 对所有内容进行编码。

示例

http://www.example.com/cgi-bin/script.sh?var1=Hello%20World!&var2=This%20is%20a%20Test.&

服务器应仅通过 “跨源资源共享”(CORS)进行通信,以使请求更安全。在本示例中,我们使用 “CORS ”来确定要使用的数据类型。

我们可以选择多种数据类型,最常见的有...

  • text/html

  • text/plain

  • application/json

发送请求时,服务器还会创建许多环境变量。目前,最重要的环境变量是 $REQUEST_METHOD 和 $QUERY_STRING。

请求方法必须是 GET,而不是其他!

查询字符串包括所有 html 结束编码的数据。

脚本

#!/bin/bash

# CORS is the way to communicate, so lets response to the server first
echo "Content-type: text/html" # set the data-type we want to use
echo "" # we don't need more rules, the empty line initiate this.

# CORS are set in stone and any communication from now on will be like reading a html-document.
# Therefor we need to create any stdout in html format!

# create html scructure and send it to stdout
echo "<!DOCTYPE html>"
echo "<html><head>"

# The content will be created depending on the Request Method
if [ "$REQUEST_METHOD" = "GET" ]; then
    # Note that the environment variables $REQUEST_METHOD and $QUERY_STRING can be processed by the shell directly.
    # One must filter the input to avoid cross site scripting.

    Var1=$(echo "$QUERY_STRING" | sed -n 's/^.*var1=\([^&]*\).*$/\1/p') # read value of "var1"
    Var1_Dec=$(echo -e $(echo "$Var1" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;')) # html decode

    Var2=$(echo "$QUERY_STRING" | sed -n 's/^.*var2=\([^&]*\).*$/\1/p')
    Var2_Dec=$(echo -e $(echo "$Var2" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;'))

    # create content for stdout
    echo "<title>Bash-CGI Example 1</title>"
    echo "</head><body>"
    echo "<h1>Bash-CGI Example 1</h1>"
    echo "<p>QUERY_STRING: ${QUERY_STRING}<br>var1=${Var1_Dec}<br>var2=${Var2_Dec}</p>" # print the values to stdout

else
    echo "<title>456 Wrong Request Method</title>"
    echo "</head><body>"
    echo "<h1>456</h1>"
    echo "<p>Requesting data went wrong.<br>The Request method has to be \"GET\" only!</p>"

fi

echo "<hr>"
echo "$SERVER_SIGNATURE" # an other environment variable
echo "</body></html>" # close html

exit 0

The html-document will look like this ...

<html><head>
<title>Bash-CGI Example 1</title>
</head><body>
<h1>Bash-CGI Example 1</h1>
<p>QUERY_STRING: var1=Hello%20World!&amp;var2=This%20is%20a%20Test.&amp;<br>var1=Hello World!<br>var2=This is a Test.</p>
<hr>
<address>Apache/2.4.10 (Debian) Server at example.com Port 80</address>

</body></html>

变量的输出将如下所示 ...

var1=Hello%20World!&var2=This%20is%20a%20Test.&
Hello World!
This is a Test.
Apache/2.4.10 (Debian) Server at example.com Port 80

负面影响...

  • 所有的编码和解码看起来不美观,但却是必要的

  • 请求可被公众读取并留下一个 trap

  • 请求的大小受到限制

  • 需要防止跨侧脚本攻击 (XSS)

Section 59.2: 请求方法:POST /w JSON

将请求方法 POST 与 SSL 结合使用可使数据传输更加安全。

此外

  • 大部分编码和解码不再需要

  • 任何人都能看到 URL,因此需要对 URL 进行编码。

数据将单独发送,因此需要通过 SSL 加密

  • 数据大小几乎不受限制

  • 仍然需要防止跨侧脚本攻击 (XSS)

为了保持展示的简单性,我们希望接收 JSON 数据,并通过跨源资源共享(CORS)进行通信。

以下脚本还将演示两种不同的内容类型。

#!/bin/bash

exec 2>/dev/null # We don't want any error messages be printed to stdout
trap "response_with_html && exit 0" ERR # response with an html message when an error occurred and close the script

function response_with_html(){
    echo "Content-type: text/html"
    echo ""
    echo "<!DOCTYPE html>"
    echo "<html><head>"
    echo "<title>456</title>"
    echo "</head><body>"
    echo "<h1>456</h1>"
    echo "<p>Attempt to communicate with the server went wrong.</p>"
    echo "<hr>"
    echo "$SERVER_SIGNATURE"
    echo "</body></html>"
}

function response_with_json(){
    echo "Content-type: application/json"
    echo ""
    echo "{\"message\": \"Hello World!\"}"
}

if [ "$REQUEST_METHOD" = "POST" ]; then

    # The environment variabe $CONTENT_TYPE describes the data-type received
    case "$CONTENT_TYPE" in
    application/json)
        # The environment variabe $CONTENT_LENGTH describes the size of the data
        read -n "$CONTENT_LENGTH" QUERY_STRING_POST # read datastream

        # The following lines will prevent XSS and check for valide JSON-Data.
        # But these Symbols need to be encoded somehow before sending to this script
        QUERY_STRING_POST=$(echo "$QUERY_STRING_POST" | sed "s/'//g" | sed
    's/\$//g;s/`//g;s/\*//g;s/\\//g' ) # removes some symbols (like \ * ` $ ') to prevent XSS with Bash and SQL.
        QUERY_STRING_POST=$(echo "$QUERY_STRING_POST" | sed -e :a -e 's/<[^>]*>//g;/</N;//ba') # removes most html declarations to prevent XSS within documents
        JSON=$(echo "$QUERY_STRING_POST" | jq .) # json encode - This is a pretty save way to check for valide json code
    ;;
    *)
        response_with_html
        exit 0
    ;;
    esac
else
    response_with_html
    exit 0
fi

# Some Commands ...

response_with_json

exit 0

通过 POST 向本脚本发送 JSON 数据时,您将收到{“message”: “Hello World!”} 作为答案。其他所有内容都将接收 HTML 文档。

重要的还有变量 $JSON。该变量不含 XSS,但仍有可能存在错误值,因此需要首先进行验证。请记住这一点。

此代码在没有 JSON 的情况下也能正常工作。

您可以用这种方法获取任何数据。

您只需根据需要更改 Content-Type。

示例

if [ "$REQUEST_METHOD" = "POST" ]; then
    case "$CONTENT_TYPE" in
    application/x-www-form-urlencoded)
        read -n "$CONTENT_LENGTH" QUERY_STRING_POST
    text/plain)
        read -n "$CONTENT_LENGTH" QUERY_STRING_POST
    ;;
    esac
fi

最后但并非最不重要的一点是,不要忘记回复所有请求,否则第三方程序将无法知道他们是否成功了