Skip to content

Commit ac20eaf

Browse files
committed
Add qhelp for Ruby SSRF
1 parent 2bba31e commit ac20eaf

File tree

4 files changed

+71
-1
lines changed

4 files changed

+71
-1
lines changed

ruby/ql/lib/codeql/ruby/security/ServerSideRequestForgeryCustomizations.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ private import codeql.ruby.dataflow.RemoteFlowSources
1111
private import codeql.ruby.Concepts
1212
private import codeql.ruby.dataflow.Sanitizers
1313

14+
/**
15+
* Provides default sources, sinks and sanitizers for reasoning about
16+
* server side request forgery, as well as extension points for adding your own.
17+
*/
1418
module ServerSideRequestForgery {
1519
/**
1620
* A data flow source for server side request forgery vulnerabilities.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
7+
<overview>
8+
<p>Directly incorporating user input into an HTTP request without validating the input
9+
can facilitate server-side request forgery (SSRF) attacks. In these attacks, the
10+
request may be changed, directed at a different server, or via a different
11+
protocol. This can allow the attacker to obtain sensitive information or perform
12+
actions with escalated privilege.
13+
</p>
14+
15+
</overview>
16+
<recommendation>
17+
18+
<p>To guard against SSRF attacks you should avoid putting user-provided input
19+
directly into a request URL. Instead, maintain a list of authorized
20+
URLs on the server; then choose from that list based on the input provided.
21+
Alternatively, ensure requests constructed from user input are limited to
22+
a particular host or more restrictive URL prefix.</p>
23+
24+
</recommendation>
25+
<example>
26+
27+
<p>The following example shows an HTTP request parameter being used directly to form a
28+
new request without validating the input, which facilitates SSRF attacks.
29+
It also shows how to remedy the problem by validating the user input against a known fixed string.
30+
</p>
31+
32+
<sample src="ServerSideRequestForgery.rb" />
33+
34+
</example>
35+
<references>
36+
<li>
37+
<a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">OWASP SSRF</a>
38+
</li>
39+
40+
</references>
41+
</qhelp>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
require "excon"
2+
require "json"
3+
4+
class PostsController < ActionController::Base
5+
def create
6+
user = params[:user_id]
7+
8+
# BAD - user can control the entire URL of the request
9+
users_service_domain = params[:users_service_domain]
10+
response = Excon.post("#{users_service_domain}/logins", body: {user_id: user}).body
11+
token = JSON.parse(response)["token"]
12+
13+
# GOOD - path is validated against a known fixed string
14+
path = if params[:users_service_path] == "v1/users"
15+
"v1/users"
16+
else
17+
"v2/users"
18+
end
19+
response = Excon.post("users-service/#{path}", body: {user_id: user}).body
20+
token = JSON.parse(response)["token"]
21+
22+
@post = Post.create(params[:post].merge(user_token: token))
23+
render @post
24+
end
25+
end

ruby/ql/test/query-tests/security/cwe-918/ServerSideRequestForgery.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "Excon"
1+
require "excon"
22
require "json"
33

44
class PostsController < ActionController::Base

0 commit comments

Comments
 (0)