1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
Description: limit fetching file size & disable XML entity expansion
This prevents possible XML denial of service attacks [CVE-2013-1812]
Author: nov matake <nov@matake.jp>
Origin: https://github.com/openid/ruby-openid/commit/a3693cef06049563f5b4e4824f4d3211288508ed
Bug: https://github.com/openid/ruby-openid/pull/43
Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=702217
Reviewed-by: Cédric Boutillier <boutil@debian.org>
Last-Update: 2012-10-23
---
lib/openid/fetchers.rb | 17 ++++++++++++++---
lib/openid/yadis/xrds.rb | 34 ++++++++++++++++++++++------------
2 files changed, 36 insertions(+), 15 deletions(-)
--- a/lib/openid/fetchers.rb
+++ b/lib/openid/fetchers.rb
@@ -10,7 +10,7 @@
require 'net/http'
end
-MAX_RESPONSE_KB = 1024
+MAX_RESPONSE_KB = 10485760 # 10 MB (can be smaller, I guess)
module Net
class HTTP
@@ -192,6 +192,16 @@
conn = make_connection(url)
response = nil
+ whole_body = ''
+ body_size_limitter = lambda do |r|
+ r.read_body do |partial| # read body now
+ whole_body << partial
+ if whole_body.length > MAX_RESPONSE_KB
+ raise FetchingError.new("Response Too Large")
+ end
+ end
+ whole_body
+ end
response = conn.start {
# Check the certificate against the URL's hostname
if supports_ssl?(conn) and conn.use_ssl?
@@ -199,13 +209,12 @@
end
if body.nil?
- conn.request_get(url.request_uri, headers)
+ conn.request_get(url.request_uri, headers, &body_size_limitter)
else
headers["Content-type"] ||= "application/x-www-form-urlencoded"
- conn.request_post(url.request_uri, body, headers)
+ conn.request_post(url.request_uri, body, headers, &body_size_limitter)
end
}
- setup_encoding(response)
rescue Timeout::Error => why
raise FetchingError, "Error fetching #{url}: #{why}"
rescue RuntimeError => why
@@ -232,7 +241,10 @@
raise FetchingError, "Error encountered in redirect from #{url}: #{why}"
end
else
- return HTTPResponse._from_net_response(response, unparsed_url)
+ response = HTTPResponse._from_net_response(response, unparsed_url)
+ response.body = whole_body
+ setup_encoding(response)
+ return response
end
end
--- a/lib/openid/yadis/xrds.rb
+++ b/lib/openid/yadis/xrds.rb
@@ -88,23 +88,33 @@
end
def Yadis::parseXRDS(text)
- if text.nil?
- raise XRDSError.new("Not an XRDS document.")
- end
+ disable_entity_expansion do
+ if text.nil?
+ raise XRDSError.new("Not an XRDS document.")
+ end
- begin
- d = REXML::Document.new(text)
- rescue RuntimeError => why
- raise XRDSError.new("Not an XRDS document. Failed to parse XML.")
- end
+ begin
+ d = REXML::Document.new(text)
+ rescue RuntimeError => why
+ raise XRDSError.new("Not an XRDS document. Failed to parse XML.")
+ end
- if is_xrds?(d)
- return d
- else
- raise XRDSError.new("Not an XRDS document.")
+ if is_xrds?(d)
+ return d
+ else
+ raise XRDSError.new("Not an XRDS document.")
+ end
end
end
+ def Yadis::disable_entity_expansion
+ _previous_ = REXML::Document::entity_expansion_limit
+ REXML::Document::entity_expansion_limit = 0
+ yield
+ ensure
+ REXML::Document::entity_expansion_limit = _previous_
+ end
+
def Yadis::is_xrds?(xrds_tree)
xrds_root = xrds_tree.root
return (!xrds_root.nil? and
|