-
Notifications
You must be signed in to change notification settings - Fork 2k
[Python] CWE-348: Client supplied ip used in security check #6214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
yoff
merged 8 commits into
github:main
from
haby0:python/ClientSuppliedIpUsedInSecurityCheck
Oct 11, 2021
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
b866f1b
Add CWE-348 ClientSuppliedIpUsedInSecurityCheck
haby0 e8d0827
Add tornado source
haby0 9e63aa9
Update query
haby0 0277601
Eliminate false positives caused by `.`
haby0 9b969e1
Modify according to @yoff suggestion
haby0 a17b0d4
Modify Sanitizer
haby0 538bf7c
Update python/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUs…
haby0 c2d0fcf
Update python/ql/test/experimental/query-tests/Security/CWE-348/Clien…
haby0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
35 changes: 35 additions & 0 deletions
35
python/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #!/usr/bin/env python | ||
| # -*- coding: UTF-8 -*- | ||
| """ | ||
| @Desc :ip address spoofing | ||
| """ | ||
| from flask import Flask | ||
| from flask import request | ||
|
|
||
| app = Flask(__name__) | ||
|
|
||
| @app.route('/bad1') | ||
| def bad1(): | ||
| client_ip = request.headers.get('x-forwarded-for') | ||
| if not client_ip.startswith('192.168.'): | ||
| raise Exception('ip illegal') | ||
| return 'bad1' | ||
|
|
||
| @app.route('/bad2') | ||
| def bad2(): | ||
| client_ip = request.headers.get('x-forwarded-for') | ||
| if not client_ip == '127.0.0.1': | ||
| raise Exception('ip illegal') | ||
| return 'bad2' | ||
|
|
||
| @app.route('/good1') | ||
| def good1(): | ||
| client_ip = request.headers.get('x-forwarded-for') | ||
| client_ip = client_ip.split(',')[client_ip.split(',').length - 1] | ||
| if not client_ip == '127.0.0.1': | ||
| raise Exception('ip illegal') | ||
| return 'good1' | ||
|
|
||
| if __name__ == '__main__': | ||
| app.debug = True | ||
| app.run() |
35 changes: 35 additions & 0 deletions
35
python/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qhelp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
| <overview> | ||
| <p>An original client IP address is retrieved from an http header (<code>X-Forwarded-For</code> or <code>X-Real-IP</code> or <code>Proxy-Client-IP</code> | ||
| etc.), which is used to ensure security. Attackers can forge the value of these identifiers to | ||
| bypass a ban-list, for example.</p> | ||
|
|
||
| </overview> | ||
| <recommendation> | ||
|
|
||
| <p>Do not trust the values of HTTP headers allegedly identifying the originating IP. If you are aware your application will run behind some reverse proxies then the last entry of a <code>X-Forwarded-For</code> header value may be more trustworthy than the rest of it because some reverse proxies append the IP address they observed to the end of any remote-supplied header.</p> | ||
|
|
||
| </recommendation> | ||
| <example> | ||
|
|
||
| <p>The following examples show the bad case and the good case respectively. | ||
| In <code>bad1</code> method and <code>bad2</code> method, the client ip the <code>X-Forwarded-For</code> is split into comma-separated values, but the less-trustworthy first one is used. Both of these examples could be deceived by providing a forged HTTP header. The method | ||
| <code>good1</code> similarly splits an <code>X-Forwarded-For</code> value, but uses the last, more-trustworthy entry.</p> | ||
|
|
||
| <sample src="ClientSuppliedIpUsedInSecurityCheck.py" /> | ||
|
|
||
| </example> | ||
| <references> | ||
|
|
||
| <li>Dennis Schneider: <a href="https://www.dennis-schneider.com/blog/prevent-ip-address-spoofing-with-x-forwarded-for-header-and-aws-elb-in-clojure-ring/"> | ||
| Prevent IP address spoofing with X-Forwarded-For header when using AWS ELB and Clojure Ring</a> | ||
| </li> | ||
|
|
||
| <li>Security Rule Zero: <a href="https://www.f5.com/company/blog/security-rule-zero-a-warning-about-x-forwarded-for">A Warning about X-Forwarded-For</a> | ||
| </li> | ||
|
|
||
| </references> | ||
| </qhelp> |
56 changes: 56 additions & 0 deletions
56
python/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| /** | ||
| * @name IP address spoofing | ||
| * @description A remote endpoint identifier is read from an HTTP header. Attackers can modify the value | ||
| * of the identifier to forge the client ip. | ||
| * @kind path-problem | ||
| * @problem.severity error | ||
| * @precision high | ||
| * @id py/ip-address-spoofing | ||
| * @tags security | ||
| * external/cwe/cwe-348 | ||
| */ | ||
|
|
||
| import python | ||
| import semmle.python.dataflow.new.DataFlow | ||
| import semmle.python.dataflow.new.TaintTracking | ||
| import semmle.python.ApiGraphs | ||
| import ClientSuppliedIpUsedInSecurityCheckLib | ||
| import DataFlow::PathGraph | ||
|
|
||
| /** | ||
| * Taint-tracking configuration tracing flow from obtaining a client ip from an HTTP header to a sensitive use. | ||
| */ | ||
| class ClientSuppliedIpUsedInSecurityCheckConfig extends TaintTracking::Configuration { | ||
| ClientSuppliedIpUsedInSecurityCheckConfig() { this = "ClientSuppliedIpUsedInSecurityCheckConfig" } | ||
|
|
||
| override predicate isSource(DataFlow::Node source) { | ||
| source instanceof ClientSuppliedIpUsedInSecurityCheck | ||
| } | ||
|
|
||
| override predicate isSink(DataFlow::Node sink) { sink instanceof PossibleSecurityCheck } | ||
|
|
||
| override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { | ||
| exists(DataFlow::CallCfgNode ccn | | ||
| ccn = API::moduleImport("netaddr").getMember("IPAddress").getACall() and | ||
| ccn.getArg(0) = pred and | ||
| ccn = succ | ||
| ) | ||
| } | ||
|
|
||
| override predicate isSanitizer(DataFlow::Node node) { | ||
| // `client_supplied_ip.split(",")[n]` for `n` > 0 | ||
| exists(Subscript ss | | ||
| not ss.getIndex().(IntegerLiteral).getText() = "0" and | ||
| ss.getObject().(Call).getFunc().(Attribute).getName() = "split" and | ||
| ss.getObject().(Call).getAnArg().(StrConst).getText() = "," and | ||
| ss = node.asExpr() | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| from | ||
| ClientSuppliedIpUsedInSecurityCheckConfig config, DataFlow::PathNode source, | ||
| DataFlow::PathNode sink | ||
| where config.hasFlowPath(source, sink) | ||
| select sink.getNode(), source, sink, "IP address spoofing might include code from $@.", | ||
| source.getNode(), "this user input" |
152 changes: 152 additions & 0 deletions
152
python/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheckLib.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| private import python | ||
| private import semmle.python.Concepts | ||
| private import semmle.python.ApiGraphs | ||
| private import semmle.python.dataflow.new.DataFlow | ||
| private import semmle.python.dataflow.new.RemoteFlowSources | ||
|
|
||
| /** | ||
| * A data flow source of the client ip obtained according to the remote endpoint identifier specified | ||
| * (`X-Forwarded-For`, `X-Real-IP`, `Proxy-Client-IP`, etc.) in the header. | ||
| * | ||
| * For example: `request.headers.get("X-Forwarded-For")`. | ||
| */ | ||
| abstract class ClientSuppliedIpUsedInSecurityCheck extends DataFlow::CallCfgNode { } | ||
|
|
||
| private class FlaskClientSuppliedIpUsedInSecurityCheck extends ClientSuppliedIpUsedInSecurityCheck { | ||
| FlaskClientSuppliedIpUsedInSecurityCheck() { | ||
| exists(RemoteFlowSource rfs, DataFlow::AttrRead get | | ||
| rfs.getSourceType() = "flask.request" and this.getFunction() = get | ||
| | | ||
| // `get` is a call to request.headers.get or request.headers.get_all or request.headers.getlist | ||
| // request.headers | ||
| get.getObject() | ||
| .(DataFlow::AttrRead) | ||
| // request | ||
| .getObject() | ||
| .getALocalSource() = rfs and | ||
| get.getAttributeName() in ["get", "get_all", "getlist"] and | ||
| get.getObject().(DataFlow::AttrRead).getAttributeName() = "headers" and | ||
| this.getArg(0).asExpr().(StrConst).getText().toLowerCase() = clientIpParameterName() | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| private class DjangoClientSuppliedIpUsedInSecurityCheck extends ClientSuppliedIpUsedInSecurityCheck { | ||
| DjangoClientSuppliedIpUsedInSecurityCheck() { | ||
| exists(RemoteFlowSource rfs, DataFlow::AttrRead get | | ||
| rfs.getSourceType() = "django.http.request.HttpRequest" and this.getFunction() = get | ||
| | | ||
| // `get` is a call to request.headers.get or request.META.get | ||
| // request.headers | ||
| get.getObject() | ||
| .(DataFlow::AttrRead) | ||
| // request | ||
| .getObject() | ||
| .getALocalSource() = rfs and | ||
| get.getAttributeName() = "get" and | ||
| get.getObject().(DataFlow::AttrRead).getAttributeName() in ["headers", "META"] and | ||
| this.getArg(0).asExpr().(StrConst).getText().toLowerCase() = clientIpParameterName() | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| private class TornadoClientSuppliedIpUsedInSecurityCheck extends ClientSuppliedIpUsedInSecurityCheck { | ||
| TornadoClientSuppliedIpUsedInSecurityCheck() { | ||
| exists(RemoteFlowSource rfs, DataFlow::AttrRead get | | ||
| rfs.getSourceType() = "tornado.web.RequestHandler" and this.getFunction() = get | ||
| | | ||
| // `get` is a call to `rfs`.request.headers.get | ||
| // `rfs`.request.headers | ||
| get.getObject() | ||
| .(DataFlow::AttrRead) | ||
| // `rfs`.request | ||
| .getObject() | ||
| .(DataFlow::AttrRead) | ||
| // `rfs` | ||
| .getObject() | ||
| .getALocalSource() = rfs and | ||
| get.getAttributeName() in ["get", "get_list"] and | ||
| get.getObject().(DataFlow::AttrRead).getAttributeName() = "headers" and | ||
| this.getArg(0).asExpr().(StrConst).getText().toLowerCase() = clientIpParameterName() | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| private string clientIpParameterName() { | ||
| result in [ | ||
| "x-forwarded-for", "x_forwarded_for", "x-real-ip", "x_real_ip", "proxy-client-ip", | ||
| "proxy_client_ip", "wl-proxy-client-ip", "wl_proxy_client_ip", "http_x_forwarded_for", | ||
| "http-x-forwarded-for", "http_x_forwarded", "http_x_cluster_client_ip", "http_client_ip", | ||
| "http_forwarded_for", "http_forwarded", "http_via", "remote_addr" | ||
| ] | ||
| } | ||
|
|
||
| /** A data flow sink for ip address forgery vulnerabilities. */ | ||
| abstract class PossibleSecurityCheck extends DataFlow::Node { } | ||
|
|
||
| /** A data flow sink for sql operation. */ | ||
| private class SqlOperationAsSecurityCheck extends PossibleSecurityCheck { | ||
| SqlOperationAsSecurityCheck() { this = any(SqlExecution e).getSql() } | ||
| } | ||
|
|
||
| /** | ||
| * A data flow sink for remote client ip comparison. | ||
| * | ||
| * For example: `if not ipAddr.startswith('192.168.') : ...` determine whether the client ip starts | ||
| * with `192.168.`, and the program can be deceived by forging the ip address. | ||
| */ | ||
| private class CompareSink extends PossibleSecurityCheck { | ||
| CompareSink() { | ||
| exists(Call call | | ||
| call.getFunc().(Attribute).getName() = "startswith" and | ||
| call.getArg(0).(StrConst).getText().regexpMatch(getIpAddressRegex()) and | ||
| not call.getArg(0).(StrConst).getText() = "0:0:0:0:0:0:0:1" and | ||
| call.getFunc().(Attribute).getObject() = this.asExpr() | ||
| ) | ||
| or | ||
| exists(Compare compare | | ||
| ( | ||
| compare.getOp(0) instanceof Eq or | ||
| compare.getOp(0) instanceof NotEq | ||
| ) and | ||
| ( | ||
| compare.getLeft() = this.asExpr() and | ||
| compare.getComparator(0).(StrConst).getText() instanceof PrivateHostName and | ||
| not compare.getComparator(0).(StrConst).getText() = "0:0:0:0:0:0:0:1" | ||
| or | ||
| compare.getComparator(0) = this.asExpr() and | ||
| compare.getLeft().(StrConst).getText() instanceof PrivateHostName and | ||
| not compare.getLeft().(StrConst).getText() = "0:0:0:0:0:0:0:1" | ||
| ) | ||
| ) | ||
| or | ||
| exists(Compare compare | | ||
| ( | ||
| compare.getOp(0) instanceof In or | ||
| compare.getOp(0) instanceof NotIn | ||
| ) and | ||
| ( | ||
| compare.getLeft() = this.asExpr() | ||
| or | ||
| compare.getComparator(0) = this.asExpr() and | ||
| not compare.getLeft().(StrConst).getText() in ["%", ",", "."] | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| string getIpAddressRegex() { | ||
| result = | ||
| "^((10\\.((1\\d{2})?|(2[0-4]\\d)?|(25[0-5])?|([1-9]\\d|[0-9])?)(\\.)?)|(192\\.168\\.)|172\\.(1[6789]|2[0-9]|3[01])\\.)((1\\d{2})?|(2[0-4]\\d)?|(25[0-5])?|([1-9]\\d|[0-9])?)(\\.)?((1\\d{2})?|(2[0-4]\\d)?|(25[0-5])?|([1-9]\\d|[0-9])?)$" | ||
| } | ||
|
|
||
| /** | ||
| * A string matching private host names of IPv4 and IPv6, which only matches the host portion therefore checking for port is not necessary. | ||
| * Several examples are localhost, reserved IPv4 IP addresses including 127.0.0.1, 10.x.x.x, 172.16.x,x, 192.168.x,x, and reserved IPv6 addresses including [0:0:0:0:0:0:0:1] and [::1] | ||
| */ | ||
| private class PrivateHostName extends string { | ||
| bindingset[this] | ||
| PrivateHostName() { | ||
| this.regexpMatch("(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?") | ||
| } | ||
| } | ||
16 changes: 16 additions & 0 deletions
16
...st/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| edges | ||
| | flask_bad.py:13:17:13:54 | ControlFlowNode for Attribute() | flask_bad.py:14:12:14:20 | ControlFlowNode for client_ip | | ||
| | flask_bad.py:20:17:20:54 | ControlFlowNode for Attribute() | flask_bad.py:21:12:21:20 | ControlFlowNode for client_ip | | ||
| | tornado_bad.py:22:25:22:69 | ControlFlowNode for Attribute() | tornado_bad.py:23:16:23:24 | ControlFlowNode for client_ip | | ||
| nodes | ||
| | flask_bad.py:13:17:13:54 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | ||
| | flask_bad.py:14:12:14:20 | ControlFlowNode for client_ip | semmle.label | ControlFlowNode for client_ip | | ||
| | flask_bad.py:20:17:20:54 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | ||
| | flask_bad.py:21:12:21:20 | ControlFlowNode for client_ip | semmle.label | ControlFlowNode for client_ip | | ||
| | tornado_bad.py:22:25:22:69 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | ||
| | tornado_bad.py:23:16:23:24 | ControlFlowNode for client_ip | semmle.label | ControlFlowNode for client_ip | | ||
| subpaths | ||
| #select | ||
|
haby0 marked this conversation as resolved.
|
||
| | flask_bad.py:14:12:14:20 | ControlFlowNode for client_ip | flask_bad.py:13:17:13:54 | ControlFlowNode for Attribute() | flask_bad.py:14:12:14:20 | ControlFlowNode for client_ip | IP address spoofing might include code from $@. | flask_bad.py:13:17:13:54 | ControlFlowNode for Attribute() | this user input | | ||
| | flask_bad.py:21:12:21:20 | ControlFlowNode for client_ip | flask_bad.py:20:17:20:54 | ControlFlowNode for Attribute() | flask_bad.py:21:12:21:20 | ControlFlowNode for client_ip | IP address spoofing might include code from $@. | flask_bad.py:20:17:20:54 | ControlFlowNode for Attribute() | this user input | | ||
| | tornado_bad.py:23:16:23:24 | ControlFlowNode for client_ip | tornado_bad.py:22:25:22:69 | ControlFlowNode for Attribute() | tornado_bad.py:23:16:23:24 | ControlFlowNode for client_ip | IP address spoofing might include code from $@. | tornado_bad.py:22:25:22:69 | ControlFlowNode for Attribute() | this user input | | ||
1 change: 1 addition & 0 deletions
1
.../test/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql |
27 changes: 27 additions & 0 deletions
27
python/ql/test/experimental/query-tests/Security/CWE-348/flask_bad.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #!/usr/bin/env python | ||
| # -*- coding: UTF-8 -*- | ||
| """ | ||
| @Desc :ip address spoofing | ||
| """ | ||
| from flask import Flask | ||
| from flask import request | ||
|
|
||
| app = Flask(__name__) | ||
|
|
||
| @app.route('/bad1') | ||
| def bad1(): | ||
| client_ip = request.headers.get('x-forwarded-for') | ||
| if not client_ip.startswith('192.168.'): | ||
| raise Exception('ip illegal') | ||
| return 'bad1' | ||
|
|
||
| @app.route('/bad2') | ||
| def bad2(): | ||
| client_ip = request.headers.get('x-forwarded-for') | ||
| if not client_ip == '127.0.0.1': | ||
| raise Exception('ip illegal') | ||
| return 'bad2' | ||
|
|
||
| if __name__ == '__main__': | ||
| app.debug = True | ||
| app.run() |
21 changes: 21 additions & 0 deletions
21
python/ql/test/experimental/query-tests/Security/CWE-348/flask_good.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| #!/usr/bin/env python | ||
| # -*- coding: UTF-8 -*- | ||
| """ | ||
| @Desc :ip address spoofing | ||
| """ | ||
| from flask import Flask | ||
| from flask import request | ||
|
|
||
| app = Flask(__name__) | ||
|
|
||
| @app.route('/good1') | ||
| def good1(): | ||
| client_ip = request.headers.get('x-forwarded-for') | ||
| client_ip = client_ip.split(',')[len(client_ip.split(',')) - 1] | ||
| if not client_ip == '127.0.0.1': | ||
| raise Exception('ip illegal') | ||
| return 'good1' | ||
|
|
||
| if __name__ == '__main__': | ||
| app.debug = True | ||
| app.run() |
36 changes: 36 additions & 0 deletions
36
python/ql/test/experimental/query-tests/Security/CWE-348/tornado_bad.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #!/usr/bin/env python | ||
| # -*- coding: UTF-8 -*- | ||
| """ | ||
| @Desc :ip address spoofing | ||
| """ | ||
| import tornado.httpserver | ||
| import tornado.options | ||
| import tornado.web | ||
| import tornado.ioloop | ||
|
|
||
| from tornado.options import define, options | ||
|
|
||
| define("port", default=8000, help="run on the given port,default 8000", type=int) | ||
|
|
||
|
|
||
| class IndexHandler(tornado.web.RequestHandler): | ||
| def get(self): | ||
| client_ip = self.request.headers.get('x-forwarded-for') | ||
| if client_ip: | ||
| client_ip = client_ip.split(',')[len(client_ip.split(',')) - 1] | ||
| else: | ||
| client_ip = self.request.headers.get('REMOTE_ADDR', None) | ||
| if not client_ip == '127.0.0.1': | ||
| raise Exception('ip illegal') | ||
| self.write("hello.") | ||
|
|
||
| handlers = [(r"/", IndexHandler)] | ||
|
|
||
| if __name__ == "__main__": | ||
| tornado.options.parse_command_line() | ||
| app = tornado.web.Application( | ||
| handlers | ||
| ) | ||
| http_server = tornado.httpserver.HTTPServer(app) | ||
| http_server.listen(options.port) | ||
| tornado.ioloop.IOLoop.instance().start() |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rename this to
ClientSuppliedIp(and similarly drop the suffix on all the implementations) since that is what we know about these nodes. It also reads better in the configuration: "A client supplied IP (source) flows to a security check (sink)".