Edition 1
$ gem cert --build <email address> ... $ chmod 600 gem-private_key.pem gem-public_cert.pem
$ openssl rsa -des3 -in <private key> -out <encrypted private key>
s.cert_chain = <path to public certificate> s.signing_key = <path to private key> if $0 =~ /gem\z/
$ gem spec testgem-1.0.0.gem cert_chain ... $ tar tf testgem-1.0.0.gem data.tar.gz metadata.gz data.tar.gz.sig metadata.gz.sig
$ gem install -P HighSecurity testgem
HighSecurity. With MediumSecurity, attacker can always intercept gem, strip signatures, modify it and serve users that accept unsigned gems.
$ gem cert --add <certificate>
~/.gem/trust directory. Name of the certificate will contain hexdigest of the subject of certificate, so if users adds another certificate with the same subject as one of the already trusted ones, original one will be overwritten without notice.
$ openssl x509 -text -in <certificate> | grep Subject: Subject: CN=test, DC=example, DC=com $ gem cert --list ...
$ bundle install --trust-policy=HighSecurity
gem 'jquery-datatables-rails', git: 'git://github.com/rweng/jquery-datatables-rails.git'bypass security policy, as they are not installed using
gem command, but cloned into bundler folder.
bundler_signature_check can be used to check Gemfile and determine which gems are signed, with suggestion which security policy can be currently safely used (note that bundler_signature_check is signed and it`s dependencies bundler and rake are likely already installed, so HighSecurity can be used):
$ gem install -P HighSecurity bundler_signature_check $ bundler_signature_check ...
$ gem install -P MediumSecurity brakeman
$ brakeman -o report.html --path <path to rails app>
-f flag. Currently supported formats are html,json,tabs, csv and text.
+------------+-------+--------+-------------------+-----------------------------------------+ | Confidence | Class | Method | Warning Type | Message | +------------+-------+--------+-------------------+-----------------------------------------+ | High | Foo | bar | Denial of Service | Symbol conversion from unsafe String .. |
High, Medium and Weak.
$ brakeman --rakewhich creates file
lib/tasks/brakeman.rake
$ brakeman -C <config file> <options>which can be later used:
$ brakeman -c <config file>
$ brakeman --compare <old result in json> -o <output in json>The output is always in json (
-f is ignored).
$ brakeman -w <level>where level
1 indicates Weak confidence, level 2 Medium and 3 High confidence.
$ brakeman -s <comma separated list of methods>
escapeHTML) and safe methods specified as command line argument are added to the list.
lib directory and/or specify files to be skipped:
$ brakeman --skip-libs $ brakeman --skip-files <comma separated list of files>
ARGV), environment variables (ENV), data read from files, sockets or other streams. Environment variable PATH is exception: it is tainted only if it contains a world-writable directory.
Object.tainted?, Object.taint and Object.untaint:
>> input = gets exploitable => "exploitable\n" >> input.tainted? => true >> input.untaint => "exploitable\n" >> input.tainted? => false
Object.untrusted?, Object.untrust and Object.trust.
Object.tainted?, Object.taint and Object.untaint. This change comes together with removal of safe level 4, which makes trust flag useless (see issue on ruby-lang or read below).
$SAFE. There are 5 possible levels: 0,1,2,3,4 with 0 being default safe level. $SAFE is thread-local and its value can only be increased (at least in theory - in practice there are well known ways how to work around restricted code execution or decrease a safe level. See Section 2.1.3.1, “Security considerations of $SAFE”). Safe level can be changed by assigning to $SAFE or with -T<level> argument.
eval, require etc.)
$SAFE is inherently flawed. Blacklist approach is used to restrict operation on each level, which means any missed function creates a vulnerability. In past several security updates were related to restricted code execution and taint flag (see CVE-2005-2337, CVE-2006-3694, CVE-2008-3655, CVE-2008-3657, CVE-2011-1005, CVE-2012-4464,CVE-2012-4466 and CVE-2013-2065).
$SAFE is inherently flawed and cannot be used to run untrusted code even at the highest safe level. It must not be used as mechanism to create a secure sandbox, as attacker will be able to work around the restrictions or decrease safe level.
require 'fiddle' $SAFE = 1 input = "uname -rs".taint handle = DL.dlopen(nil) sys = Fiddle::Function.new(handle['system'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) sys.call DL::CPtr[input].to_iEven though safe level 1 should restrict execution of system commands, this can be bypassed using Fiddle library, which is an extension to translate a foreign function interface with Ruby. Exploit above bypasses safe level by passing input to system call as numeric memory offset. Since numbers as literals cannot be tainted, code cannot check taintedness of input.
eval on tainted string.
Kernel#exec, Kernel#system, backticks and %x{...}
Kernel#fork, Kernel#spawn
Kernel#load, Kernel#autoload
Kernel#require, Kernel#require_relative
DL and Fiddle module
Object#send, Object#__send__ and Object#public_send
BasicObject#instance_eval, BasicObject#instance_exec
Module#class_eval, Module#class_exec, Module#module_eval, Module#module_exec
Module#alias_method
to_sym or intern on user-supplied strings. Additionally, other methods may convert supplied arguments to symbols internally, for example Object.send, Object.instance_variable_set, Object.instance_variable_get, Module.const_get or Module.const_set:
>> Symbol.all_symbols.size => 2956 >> Module.const_get('MY_SYMBOL') NameError: uninitialized constant Module::MY_SYMBOL >> Symbol.all_symbols.size => 2957
Symbol.all_symbols class method.
rb_check_id is available to Ruby C extensions, which returns 0 when String passed as argument is not already defined as Symbol. This makes overriding default intern methods possible.
rb_check_id and provides a patch for to_sym or intern methods of String. When the conversion from String to Symbol would define a new Symbol, either nil is returned or exception raised. Such approach prohibits creating any new Symbols other than those that are already defined by the application. In case the string is trusted, new symbol can be created by calling intern(:allow_unsafe).
Marshal.dump and Marshal.load can serialize and deserialize most of the classes in Ruby. If application deserializes data from untrusted source, attacker can abuse this to execute arbitrary code. Therefore, this method is not suitable most of the time and should never be be used on data from unstrusted source.
Marshal.load it can be used to deserialize most of the Ruby classes and also should never be used on untrusted data.
Hash, Array, String etc. When application requires serialization of certain types, developer can explicitly whitelist trusted types of objects:
SafeYAML.whitelist!(FrobDispenser, GobbleFactory)This approach is more versatile, since it disables serialization of unsafe classes, yet allows developer to serialize know benign object. Requiring
safe_yaml will patch method YAML.load.
YAML and used YAML.load to deserialize.
class Range def to_json(*a) { 'json_class' => self.class.name, 'data' => [ first, last, exclude_end? ] }.to_json(*a) end def self.json_create(o) new(*o['data']) end endThis will allow instances of Range class to be serialized with JSON:
>> (1..10).to_json => "{\"json_class\":\"Range\",\"data\":[1,10,false]}"During deserialization, JSON gem will try to look up class referenced by "json_class", which might create new Symbol if the class does not exist, possibly allowing Denial of Service (see Section 2.3, “Symbols”):
>> Symbol.all_symbols.size
=> 3179
>> JSON.parse('{"json_class":"NonexistentClass"}')
ArgumentError: can't get const NonexistentClass: uninitialized constant NonexistentClass
>> Symbol.all_symbols.size
=> 3180
To disable this, :create_additions => false option can be passed as second argument:
>> JSON.parse('{"json_class":"NonexistentClass"}',:create_additions => false)
=> {"json_class"=>"NonexistentClass"}
This behaviour has changed in response to CVE-2013-0269 and JSON.parse now defaults to :create_additions => false. However, default behaviour has not changed for JSON.load, which is dangerous to call on untrusted input.
init_with() or []= methods, that get called during deserialization. This might seem like an unlikely event, however, its very likely in case of big projects like Ruby on Rails.
ActionDispatch::Routing::RouteSet::NamedRouteCollection, which contained code like this:
class NamedRouteCollection alias []= add def add(name, route) routes[name.to_sym] = route define_named_route_methods(name, route) end def define_named_route_methods(name, route) define_url_helper route, :"#{name}_path", route.defaults.merge(:use_route => name, :only_path => true) define_url_helper route, :"#{name}_url", route.defaults.merge(:use_route => name, :only_path => false) end def define_url_helper(route, name, options)@module.module_eval <<-END_EVAL def #{name}(*args) # ... code end END_EVAL end ...Even though
module_eval is hidden under several layers of method calls, calling []= effectively passes first argument to the define_url_helper, where it gets evaluated.
--- !ruby/hash:NamedRouteCollection foo; end; system 'rm /etc/passwd'; def bar: bazBefore deserialization, Ruby's YAML parser Psych first looks at the declared type, which says this object is an instance of
NamedRouteCollection and subclass of Ruby's Kernel::Hash class.
[]= method. Given YAML like
--- !ruby/hash:MyHash key1: value1 key2: value2deserialization process is equivalent to calling
newobj = MyHash.new newobj['key1'] = 'value1' newobj['key2'] = 'value2' newobj
['foo; end; system 'rm /etc/passwd'; def bar','baz']so deserialization process will call
[]= method on NamedRouteCollection with key 'foo; end; system 'rm /etc/passwd'; def bar'.
define_url_helper as an argument and following code gets evaluated:
def foo; end; system 'rm /etc/passwd'; def bar(*args) # ... code endReordering the code above to be more readable, this is equivalent to
def foo end system 'rm /etc/passwd' def bar(*args) # ... code end
^ and $ refer to the beginning and the end of a line, rather then a string. If regular expression like /^[a-z]+$ is used to whitelist user input, attacker can bypass it by including newline. To match the beginning and the end of a string use anchors \A and \z.
>> puts 'Exploited!' if /^benign$/ =~ "benign\n with exploit" Exploited! => nil >> puts 'Exploited!' if /\Abenign\z/ =~ "benign\n with exploit" => nil
Object.send is a method with serious security impact, since it invokes any method on object, including private methods. Some methods in Ruby like eval or exit! are private methods of Object and can be invoked using send:
>> Object.private_methods.include?(:eval) => true >> Object.private_methods.include?(:exit) => true >> Object.send('eval', "system 'uname'") Linux => true
Object.public_send, which by definition only invokes public methods on object. However, this does not prevent attacker from executing only private methods, since Object.send itself is (and has to be) public:
>> Object.public_send("send","eval","system 'uname'") Linux => true >> Object.public_send("send","exit!") # exits
send and public_send with user controlled arguments.
OpenSSL module included in standard library. This module is then used by other parts of standard library to manage SSL, including Net::HTTP, Net::POP, Net::IMAP, Net::SMTP and others.
VERIFY_NONE, VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT and VERIFY_CLIENT_ONCE. These correspond to underlying OpenSSL modes.
>> require 'openssl' => true >> require 'socket' => true >> tcp_client = TCPSocket.new 'redhat.com', 443 => #<TCPSocket:fd 5> >> ssl_context = OpenSSL::SSL::SSLContext.new => #<OpenSSL::SSL::SSLContext:0x00000000fcf918> >> ssl_context.set_params => {:ssl_version=>"SSLv23", :verify_mode=>1, :ciphers=>"ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", :options=>-2147480585} >> ssl_client = OpenSSL::SSL::SSLSocket.new tcp_client, ssl_context => #<OpenSSL::SSL::SSLSocket:0x0000000106a418> >> ssl_client.connect => #<OpenSSL::SSL::SSLSocket:0x0000000106a418>Note the call to
ssl_context.set_params: by default, when context is created, all its instance variables are nil. Before using the context, set_params should be called to initialize them (when called without argument, default parameters are chosen). In case this call is omitted and variables are left uninitialized, certificate verification is not performed (effectively the same as VERIFY_NONE mode). Default parameters are stored in the constant:
>> OpenSSL::SSL::SSLContext::DEFAULT_PARAMS => {:ssl_version=>"SSLv23", :verify_mode=>1, :ciphers=>"ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", :options=>-2147480585}One of the side effects of
set_params is that it also sets up certificate store with certificates from default certificate area (see Section 2.7.1, “Certificate store” below):
>> ssl_context.cert_store => nil >> ssl_context.set_params => {:ssl_version=>"SSLv23", :verify_mode=>1, :ciphers=>"ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", :options=>-2147480585} >> ssl_context.cert_store => #<OpenSSL::X509::Store:0x00000000fea740>
OpenSSL::X509::Store implements certificate store in Ruby. Certificate store is similar to store in web browsers - it contains trusted certificates that can be used to verify certificate chain. When new certificate store is created, it contains no trusted certificates by default.
Store#add_file takes a path to DER/PEM encoded certificate
Store#add_cert takes instance of X509::Certificate
Store#add_path takes a path to a directory with trusted certificates
Store#set_default_path adds certificates stored in default certificate area
Store#set_default_path. The path to default certificate area is defined as:
>> OpenSSL::X509::DEFAULT_CERT_AREA => "/etc/pki/tls"
SSLContext, users may encounter exception from OpenSSL code saying the certificate verification failed:
>> ssl_client.connect OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed from (irb):7:in `connect' from (irb):7This usually happens when
verify_mode is set to check the certificate, but the certificate store used does not contain trusted certificate required to verify the SSL sent by the server.
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONEThis redefines constant
OpenSSL::SSL::VERIFY_PEER to have the same effect as OpenSSL::SSL::VERIFY_PEER, effectively globally disabling certificate checking.
Net::IMAP as example (the code below refers to Ruby 1.9.3): initialize method for creating a new IMAP connection has takes the following arguments:
def initialize(host, port_or_options = {}, usessl = false, certs = nil, verify = true) ...When SSL connection is used but
certs and verify arguments are left to be assigned defaults values, SSLError may be thrown when certificate sent by server cannot be verified.
SSLContext contains a trusted certificate that can be used to verify the certificate sent by the server.
VERIFY_NONE mode. The above mentioned Net::IMAP#initialize looks like this:
def initialize(host, port = PORT, usessl = false, certs = nil, verify = false) ...Starting from Ruby 1.9, standard library defaults to
VERIFY_PEER mode.
User.where("name = '#{params[:name]}'")This would be translated to following SQL query:
SELECT "users".* FROM "users" WHERE (name = 'username')Such statement is vulnerable to SQL injection, since part of the SQL statement is passed as string in argument and Rails does not perform any escaping. Malicious string can match apostrophe and bracket in the statement, the follow with semicolon as statement separator and arbitrary SQL query. At the end double hyphens are necessary to comment out superfluous apostrophe:
>> params[:name] = "'); <arbitrary statement> --"Using Rails console we can see this how such input is translated to a SQL query:
>> params[:name] = "noname'); SELECT name, password_digest FROM users where userid = 'admin' --" => "noname'); SELECT name, password_digest FROM users where userid = 'admin' --" >> User.where("name = '#{params[:name]}'") User Load (2.4ms) SELECT "users".* FROM "users" WHERE (name = 'noname'); SELECT name, password_digest FROM users where userid = 'admin' --') => [#<User name: "Administrator", password_digest: "$2a$10$m7XI628GGkdTH1JmkdMfluJyA360V1.QBtSbFMrc5Jwm...">]
User.where("name = ?", params[:name])or
User.where(name: params[:name])
ActiveRecord::sanitize method which can be used to sanitize a string explicitly.
exists? - when given string as an argument, it tries to convert it to integer, returning 0 when the conversion is impossible:
>> User.exists?("1") User Exists (0.9ms) SELECT 1 AS one FROM "users" WHERE "users"."id" = 1 LIMIT 1 => true >> User.exists?("abc") User Exists (0.8ms) SELECT 1 AS one FROM "users" WHERE "users"."id" = 0 LIMIT 1 => false
User.exists?(params[:id])
exists? method also accepts array as an argument - in which case first element of array is used directly in SQL query without escaping:
>> params[:id] = ["id = '1'"] => ["id = '1'"] >> User.exists?(params[:id]) User Exists (0.8ms) SELECT 1 AS one FROM "users" WHERE (id = '1') LIMIT 1 => true
>> params[:id] = ["1=1);UPDATE users SET password_digest='my_digest' WHERE userid='admin' --"] => ["1=1);UPDATE users SET password_digest='my_digest' WHERE userid='admin' --"] >> User.exists?(params[:id]) User Exists (67.6ms) SELECT 1 AS one FROM "users" WHERE (1=1);UPDATE users SET password_digest='my_digest' WHERE userid='admin' --) LIMIT 1 => false >> User.where(userid: 'admin').first.password_digest User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."userid" = 'admin' LIMIT 1 User Inst (0.4ms - 1rows) => "my_digest"
key[]=value
exists? method called on params[:id] then looks like this:
GET /controller/action?id[]=1 = 1);UPDATE users SET password_digest='my_digest' WHERE userid='admin' --
system "echo Hello #{params[:name]}!"user can use semicolon to terminate
echo command and invoke command of his choice:
>> params[:name] = 'Joe;rm -rf /' => "Joe;touch /tmp/abc" >> system "echo Hello #{params[:name]}" Hello Joe => true # and rm gets executed
system command can be used to explicitly separate OS command to invoke from the arguments passed to it:
system(command, *parameters)
<script>alert('Hello');</script>
https://bugzilla.redhat.com/show_bug.cgi?id=<script>alert('Hello')</script>
'<script>alert(10)</script>' is not a valid bug number nor an alias to a bug.
<script>
document.write("URL is: " + document.location.href);
<script>
http://vulnerable.com/#<script>alert('Hello')</script>
html_escape() method (or alias h()). This is methodically bad approach to security, since any omission of the method on critical place lead to potentiall exploitable weakness.
ActiveSupport::SafeBuffer class, which extends String and represents escaped (i.e. html safe) version of a string. The most important aspect of SafeBuffer is that it stays html safe even when standard String methods are called with unsafe inputs:
> sb = ActiveSupport::SafeBuffer.new => "" > sb << "<string>" => "<string>" > sb + "</string>" => "<string></string>"
html_safe method. This method actually returns an instance of SafeBuffer:
> safe = " <b>HTML safe</b> string".html_safe => " <b>HTML safe</b> string" > safe.class => ActiveSupport::SafeBuffer > sb << safe => "<string></string> <b>HTML safe</b> string"
html_safe() on untrusted strings. Example of this is CVE-2014-3531: XSS flaw in operating system name/description in Foreman. Weakness in this case was present in helper method, which returned name of the OS:
def os_name record, opts = {} "#{icon(record, opts)} #{record.to_label}".html_safe end
icon(record, opts) returns html safe string, but second part is untrusted and may contain html unsafe characters. Calling html_safe on the resulting String caused vulnerability and the fix was straightforward:
def os_name record, opts = {} icon(record, opts).html_safe << record.to_label end
begin
respond_to do |format|
format.html { render :text => "<pre>#{@host.info.to_yaml}</pre>" }
format.yml { render :text => @host.info.to_yaml }
end
rescue
...
begin
respond_to do |format|
format.html { render :text => "<pre>#{ERB::Util.html_escape(@host.info.to_yaml)}</pre>" }
format.yml { render :text => @host.info.to_yaml }
end
rescue
...
<script src="http://victimbank.com/transfermoney?to=attacker&amount=1000"/>
GET /transfermoney?to=attacker&amount=1000 HTTP/1.1 Host: victimbank.com Cookie: ...
<img>, <script> and others can be used to issue HTTP GET requests, there are other means to issue arbitrary requests against vulnerable application.
<body onload="document.getElementById('f').submit()">
<form id="f" action="http://victimbank.com/transfermoney" method="post" name="form1">
<input name="to" value="attacker">
<input name="amount" value="1000">
</form>
</body>
protect_from_forgerywhich will automatically include CSRF token in all non-get and XHR requests. The token itself is sent by the server in meta tag of the web page like this:
<meta content="authenticity_token" name="csrf-param" /> <meta content="VBlgpnibfsxm1QykEmlOCbxqLRxx7kDGr57tjE+LLZk=" name="csrf-token" />
def handle_unverified_request reset_session endIf this does not effectively log out user due to application-specific behaviour, developers should redefine
handle_unverified_token.
html_safe.
| URL | Outcome | Reason |
|---|---|---|
| http://web.company.com/~user2 | Success | |
| https://web.company.com/~user1 | Fail | Different protocol |
| http://store.company.com/~user1 | Fail | Different hostname |
| https://web.company.com:81/~user1 | Fail | Different port |
document.domain property to a fully-qualified suffix of the current hostname. When two pages have defined the same document.domain, same origin policy is not applied. However, document.domain has to be specified mutually - it is not enough for just one page to specify its document.domain. Also, when document.domain property is set, port is set to null, while still being checked. This means company.com:8080 cannot bypass same origin policy and access company.com by setting document.domain = "company.com", as their ports (null vs 80) differ.
document.domain has several issues:
document.domain = company.com, any subdomain can set its document.domain and access both of them, even though this access was not intended to be permitted.
<script src=".."><script>
<link rel="stylesheet" href="...">
<frame> and <iframe>
document.domain that provide a way to relax Same Origin Policy.
Origin header. Let's assume http://example.com/testpage is making a XMLHttpRequest against http://content.com/wanted_image. Request would contain:
GET /wanted_image HTTP/1.1 Referrer: http://example.com/testpage Origin: http://example.comIf the server allows sharing of the resource with domain that originated the request, the response would include:
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://example.com ..By sending
Access-Control-Allow-Origin header, server explicitly tells browser that this cross domain request shall be allowed. Allowed values of Access-Control-Allow-Origin are: * (denoting any domain, effectively marking the resource public) or space separated list of allowed origins (in practice, this usually contains just a single domain - one that was specified in Origin header in request).
Origin: null
gem 'rack-cors', :require => 'rack/cors'and configure Rails by modifying config/application.rb:
module YourApp
class Application < Rails::Application
# ...
config.middleware.use Rack::Cors do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :options]
end
end
end
end
This configuration permits all origins access to any resource on the server via GET, POST and OPTIONS methods. Customizing the configuration, developer of the application can restrict cross-domain acess to resources by origin, headers and methods.
<script> tag and the fact that embedding Javascript code from other domains is not resctricted by the same origin policy. Since the code references by src attribute of <script> tag is loaded, it can be used as a vehicle to carry data and return them after evaluation.
{"Key1": "Value1", "Key2": "Value2"}
When webpage requests the resource with
<source src="http://example.com/resource/1"></source>after receiving the response, browser will try to evaluate received data. Since data are not executable, interpreter would end with error and data would not be accessible to the code that requested it.
parseData can accept JSON data as argument, parse it and make it accessible to the rest of the page:
parseData({"Key1": "Value1", "Key2": "Value2"})
<script src="http://example.com/resource/1?jsonp=parseData"></script>
source tag does not fall under Same Origin Policy on the client side, browser sends normal HTTP GET request without Origin header. Server that receives request has no means to know that the request was generated on behalf of page from other domain. Since neither the browser nor the server checks this kind of cross-domain requests, last obstacle that prevents exploitation is the fact that returned response is evaluated as Javascript code.
GET /ops/change_tab/?tab_id=settings_authentication&callback=... Referrer: ... Cookie: ...Response returned by the server would look like this:
HTTP/1.1 200 OK
....
miqButtons('hide');
Element.replace("ops_tabs", "<div id=\"ops_tabs\" ...");
where ops_tabs div contained html code of the Authentication tab including form with hidden CSRF token. To exploit this vulnerability, attacker would patch Element.replace function on his page and issue a JSONP request against CFME server.
<script src='http://code.jquery.com/jquery-1.10.2.min.js'></script>
<script>
function test() {
$.ajax({
url: $( "input[name=url]" ).val() + '/ops/change_tab/?tab_id=settings_authentication',
dataType: 'jsonp'
});
};
var Element = { replace: function (a,text) {
...
}
>/script>
This way attacker can run arbitrary code on returned response from the server: since the request also contains CSRF token, it is easy for attacker to steal it and issue successful CSRF request on behalf of currently logged-in user.
X-Content-Security-Policy: experimental header originally introduced by Mozilla
X-WebKit-CSP: experimental header used in WebKit based browsers
Content-Security-Policy: a standard header proposed by W3C, that shall be used as replacement for the two abovementioned experimenal headers. However, older versions of browsers may support only experimental versions of this header, so web application developers that seek the best coverage may want to use all three headers together.
Content-Security-Policy: default-src 'none'; script-src http://example.com
<script src="http://malicious.com"></script>In Firefox this would generate following warning:
[13:16:03.713] CSP WARN: Directive script-src http://example.com:80 violated by http://malicious.com/This approach works in case of content with known origin, but this does not solve problem with inlined scripts such as
<script>exploit()</script>CSP addresses this problem by completely banning execution of any scripts or CSS inlined with
<script> or JavaScript URI and similar restrictions apply on eval() like mechanisms. This is necessary from security standpoint, however, it also means that web application developers who want to adopt CSP need to make sure their application does not make use of banned functions. To mitigate this CSP includes reporting capability via report-uri directive, reporting only mode via Content-Security-Policy-Report-Only header and ability to disable protection with 'unsafe-inline' and 'unsafe-eval' sources (see below).
script-src restricts which scripts the protected resource can execute.
object-src restricts from where the protected resource can load plugins.
style-src restricts which styles the user applies to the protected resource.
img-src restricts from where the protected resource can load images.
media-src restricts from where the protected resource can load video and audio.
frame-src restricts from where the protected resource can embed frames.
font-src restricts from where the protected resource can load fonts.
connect-src restricts which URIs the protected resource can load using script interfaces (like XMLHttpRequest).
default-src sets a default source list for all directives except sandbox. If not set, directives that are omitted permit all sources by default.
sandbox is an optional directive that specifies an HTML sandbox policy that the user agent applies to the protected resource.
report-uri specifies a URI to which the user agent sends reports about policy violation.
'none' matches nothing.
'self' matches current origin.
'unsafe-inline' allows inline JavaScript and CSS and can be used with script-src and style-src directives.
'unsafe-eval' allows eval-list mechanisms that convert text to executable script and can be used with script-src directive.
Content-Security-Policy: default-src 'none'; script-src https://cdn.example.com 'self' 'unsafe-inline'; connect-src https://api.example.com;
report-uri directive server can instruct client's user agent to send POST with JSON-formatted violation report to a specified URI.
Content-Security-Policy: ...; report-uri /csp_report_parser;Reports sent back to server about CSP violation looks like this:
{
"csp-report": {
"document-uri": "http://example.org/page.html",
"referrer": "http://evil.example.com/haxor.html",
"blocked-uri": "http://evil.example.com/image.png",
"violated-directive": "default-src 'self'",
"original-policy": "default-src 'self'; report-uri http://example.org/csp-report.cgi"
}
}
When deploying CSP it may be useful to test the policy in the wild before enforcing it. It is possible to achieve this by sending Content-Security-Policy-Report-Only header instead - this will indicate that the user agent must monitor any policy violations, but not enforce them. Combined with report-uri this gives developers tools to seamlessly deploy new CSP policy.
Content-Security-Policy-Report-Only: ...; report-uri /csp_report_parser;
Strict-Transport-Security: max-age=631138519
Strict-Transport-Security: max-age=631138519; includeSubDomains
Strict-Transport-Security: max-age=0allows the server to indicate that UA should delete HSTS policy associated with the host.
config.force_ssl = trueenables HSTS for the application.
X-XSS-Protection: 1
X-XSS-Protection: 1; mode=block
<frame> and <iframe> tags and sites can use this as a defense from clickjacking attacks.
X-Frame-Options: ALLOW-FROM https://example.com/
Content-Type that will pass web applications filters and server will store the file along with declared MIME type. When users download such file, server will include stored type in Content-Type header. However, browser's content-type sniffing algorithm will determine the correct type and ignore received Content-Type header, making the client vulnerable.
X-Content-Type-Options: nosniffheader to enforce the type sent in
Content-Type header.
gem 'secure_headers'enable its functionality by adding
ensure_security_headers directive to ApplicationController:
class ApplicationController < ActionController::Base ensure_security_headers end
::SecureHeaders::Configuration.configure do |config| config.hsts = {:max_age => 20.years.to_i, :include_subdomains => true} config.x_frame_options = 'DENY' config.x_content_type_options = "nosniff" config.x_xss_protection = {:value => 1, :mode => 'block'} config.csp = { :enforce => true, :default_src => "https://* self", :frame_src => "https://* http://*.twimg.com http://itunes.apple.com", :img_src => "https://*", :report_uri => '//example.com/uri-directive' } endIt is important to set
:enforce to true in CSP configuration, because SecureHeaders defaults to false, which indicates Content-Security-Policy-Report-Only header will be sent and the policy will not be enforced, only monitored (see Section 3.2.3, “Content Security Policy (CSP)”). SecureHeaders will also set value of :default_src to all empty directives explicitly and not rely on the user agent's behaviour.
X-Frame-Options, X-XSS-Protection and X-Content-Type-Options (see Section 3.2.7, “X-Content-Type-Options”). In case of CSP X-WebKit-CSP and X-Content-Security-Policy can be used to provide better compatibility with older Mozilla and WebKit-based browsers (see Section 3.2.3, “Content Security Policy (CSP)”).
$log.info "MIQ(agent-get): Request agent update for Proxy id [#{params[:id]}]"
1%0AMIQ(agent-get): Agent shutdown
MIQ(agent-get): Request agent update for Proxy id 1 MIQ(agent-get): Agent shutdown
%08%08%08%08%08%08%08%08%08Server id 7
MIQ(agent-get): Request agent update for Proxy id %08%08%08%08%08%08%08%08%08Server id 7
MIQ(agent-get): Request agent update for Server id 7
| Revision History | ||||||
|---|---|---|---|---|---|---|
| Revision 1-1 | Tue Feb 18 2014 | |||||
| ||||||
| Revision 1-2 | Tue Jan 28 2015 | |||||
| ||||||