Skip to content

Instantly share code, notes, and snippets.

@tompave
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tompave/1bce0c5b846c0044df89 to your computer and use it in GitHub Desktop.
Save tompave/1bce0c5b846c0044df89 to your computer and use it in GitHub Desktop.
Rack middleware guards
# Issue on github:
# https://github.com/rack/rack/issues/337
#
# Possible patch:
# https://gist.github.com/psychocandy/3130349
# but I don't like the idea of monkeypatching the standard library
#
# Rack middleware:
# http://stackoverflow.com/questions/16269897/rails-argumenterror-invalid-encoding
#
class PercentEncodingGuard
QUERY_STRING = 'QUERY_STRING'
BAD_REQUEST = [400, {}, ['Bad request']]
def initialize(app)
@app = app
end
def call(env)
begin
Rack::Utils.parse_nested_query(env[QUERY_STRING].to_s)
rescue
return BAD_REQUEST
end
@app.call(env)
end
end
# Inspired by:
# http://blog.ericrafaloff.com/how-to-break-most-rails-apps.html
# http://blog.ericrafaloff.com/breaking-rails-apps-with-encoding/
#
# A more heavyweight alternative:
# https://github.com/whitequark/rack-utf8_sanitizer
#
# I also like Thoughtbot's solution:
# http://robots.thoughtbot.com/fight-back-utf-8-invalid-byte-sequences
# "string_from_the_web".encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
class Utf8Guard
UTF_8 = 'UTF-8'
CONTENT_TYPE = 'CONTENT_TYPE'
FORM_URL_ENCODED = "application/x-www-form-urlencoded"
RACK_INPUT = 'rack.input'
QUERY_STRING = 'QUERY_STRING'
BAD_REQUEST = [400, {}, ['Bad request']]
def initialize(app)
@app = app
end
def call(env)
if env[CONTENT_TYPE] == FORM_URL_ENCODED
return BAD_REQUEST unless input_is_valid?(env[RACK_INPUT])
end
if env[QUERY_STRING].present?
return BAD_REQUEST unless valid_utf8?(env[QUERY_STRING])
end
@app.call(env)
end
private
def input_is_valid?(string_io)
string_io.rewind
valid_utf8?(string_io.read)
end
def valid_utf8?(str)
URI.decode(str).force_encoding(UTF_8).valid_encoding?
rescue
false
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment