Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Apache Wizardry - Ohio Linux 2011

4,472 views

Published on

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Apache Wizardry - Ohio Linux 2011

  1. 1. Apache WizardrySpells for conjuring your Apache HTTP Server / Rich Bowen - rbowen@apache.org
  2. 2. Shameless Plug Buy! Buy! Buy!
  3. 3. Old Hat ----> • 1.3 is end of life • 2.0 will be by the end of the year • 2.2 is now • 2.4 is tomorrow Photo CC by “Lost Albatross” - Flickr
  4. 4. URLs you need • http://slideshare.net/rbowen • http://wiki.apache.org/httpd • http://httpd.apache.org/docs/trunk/
  5. 5. Recipes Photo CC by Chemical Heritage Foundation - Flickr
  6. 6. CVE-2011-3192 (KillApache) • Exploits bug in handling of range requests • Range: requests a byte-range of a document • Range: 0-4,10-19,16-22,3-18 • Eg, single pages of a PDF document • Fixed in 2.2.20 and in trunk
  7. 7. Whats the problem? • No limit to the number or size of ranges • Ranges can overlap • Apache builds the entire response in memory before sending • Very easy to construct a range set that consumes all available RAM
  8. 8. Solutions: Best (2.2) # Drop the Range header when more than 5 ranges. # CVE-2011-3192 SetEnvIf Range (,.*?){5,} bad-range=1 RequestHeader unset Range env=bad-range # optional logging. CustomLog logs/range-CVE-2011-3192.log common env=bad-range
  9. 9. Solution 2 # Reject request when more than 5 ranges in the # Range: header -- CVE-2011-3192 RewriteEngine on RewriteCond %{HTTP:range} !(^bytes=[^,]+(,[^,]+){0,4}$|^$) RewriteRule .* - [F] • Use this for 1.3 and 2.0, because they dont have the PCRE sauce in SetEnvIf • Better yet, dont use 1.3 and 2.0
  10. 10. Other solutions • Disallow Range requests entirely RequestHeader unset Range • Limit the size of the Range header LimitRequestFieldSize 200
  11. 11. Directory listings are boring
  12. 12. Say it with styleIndexStyleSheet /styles/dir.css....odd { background-color: #eef;}.even { background-color: #fff;}
  13. 13. Caveat: Some features 2.4 only • In 2.2 and earlier, you can specify a style sheet, but no classes are added to the HTML • Useful, but not quite as useful
  14. 14. Now, with extra class <table id="indexlist"> <tr class="indexhead"><th class="indexcolicon">...<th class="indexcolname">...<th class="indexcollastmod">...<th class="indexcolsize">...<th class="indexcoldesc">... <tr class="indexbreakrow">... <tr class="even"><td class="indexcolicon">...
  15. 15. An exercise for the reader: • Nifty mouse-over effects (JS in HeaderName file?)Photo CC by Ugglan - Flickr • AJAXy file interaction of some kind? • Photo gallery, entirely based on mod_autoindex and Javascript?
  16. 16. mod_substitite • New module in 2.2 • Rewrite content using regular expressions • Syntax is identical to sed
  17. 17. s/foo/bar/ • Simple example - switch fonts LoadModule substitute_module libexec/apache2/mod_substitute.so AddOutputFilterByType SUBSTITUTE text/html Substitute s/ariel/courier/i
  18. 18. Proxying • More useful example • Proxying to back-end server that returns fully-qualified URLsLoadModule substitute_module libexec/apache2/mod_substitute.soAddOutputFilterByType SUBSTITUTE text/htmlSubstitute s/backend.local/www.example.com/ni
  19. 19. mod_security • Are you running mod_security?
  20. 20. mod_security • You should be
  21. 21. http firewall • The earlier you catch it ...
  22. 22. Holes Photo CC by Darwin Bell
  23. 23. SQL Injection # Prevent SQL injection attacks SecFilter "delete[[:space:]]+from" SecFilter "insert[[:space:]]+into" SecFilter "select.+from"23
  24. 24. Make sure you ... # Inspect POST payloads SecFilterScanPOST On # Default action set SecFilterDefaultAction "deny,log,status:406"24
  25. 25. While you’re at it # Inspect POST payloads SecFilterScanPOST On SecFilter “vidocin”25
  26. 26. Acceptable arguments# Only for the FormMail script<Location /cgi-bin/FormMail> # Reject request where the value of parameter "recipient" # does not end with "@apache.org" SecFilterSelective ARG_recipient "![a-zA-Z0-9]+@apache.org$"></Location> 26
  27. 27. Which PHP script is slagging my server? • Which process, and what is it doing? • Look at /server-status for a process list
  28. 28. Step 1: Look at top: • Run ‘top’ • Order by CPU usage • Pick off the httpd processes that are causing the problem and make note of their PIDs
  29. 29. Step 2: /server-status • Look at /server-status output • Look for the PIDs you noted • Move fast - the process may be gone already
  30. 30. /server-status
  31. 31. ExtendedStatus On • You’ll need “ExtendedStatus On” to get these details: <Location /server-status> SetHandler server-status </Location> ExtendedStatus On
  32. 32. SNI • General knowledge: SSL requires one certificate per IP address • That is, only one SSL site can be on each IP address • Limitation of SSL itself
  33. 33. SSL handshake
  34. 34. SSL handshake Certificate Hostname
  35. 35. Clearly this sucks
  36. 36. SNI
  37. 37. SNI • Server Name Indication • Passes server name in initial handshake • Simple solutions are always best
  38. 38. Caveats • You knew there would be a catch Mozilla Firefox 2.0 or later Opera 8.0 or later (the TLS 1.1 protocol must be enabled) Internet Explorer 7 (Vista or higher, not XP) or later Google Chrome (Vista or higher, not XP. OS X 10.5.7 or higher on Chrome 5.0.342.1 or newer) Safari Safari 3.2.1 and newer on Mac OS X 10.5.6 and Windows Vista or higher, not XP
  39. 39. Apache • 2.2.12 or laterListen 443# Listen for virtual host requests on all IP addressesNameVirtualHost *:443# Go ahead and accept connections for these vhosts# from non-SNI clientsSSLStrictSNIVHostCheck off<VirtualHost *:443> DocumentRoot /www/example1 ServerName www.example.com</VirtualHost><VirtualHost *:443> DocumentRoot /www/example2 ServerName www.example2.org</VirtualHost>
  40. 40. More Infohttp://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI
  41. 41. Secure mod_dav deployment • Security rule #1: Content is not writable • Corollary: Anyone telling you to ‘chmod 777’ is a monkey • Anyone telling you ‘chown apache something.php’ *might* be a monkey. Or they might be working around Apache’s annoying permissions model
  42. 42. However ... •Setting up WebDAV requires that content be writable ... •And owned by Apache •This is annoying
  43. 43. WebDAV <Directory /var/www/content> Dav On </Directory>
  44. 44. Why this is a problem • People write bad code • It’s easy to get PHP (or whatever else) to overwrite your content • Now your site is a radical terrorist site • This is a very unpleasant thing to wake up to on a Saturday morning
  45. 45. Secure DAV • It’s possible to set up Dav without having the files written by the Apache user • Sort of45
  46. 46. Two Apache Processes Primary Secondary server, server, running as running as user www user dav File System, owned by dav46
  47. 47. Two Apache Processes Read-only Running ordinary set of modules Running web apps, etc Primary server, running as user www File System, owned by dav47
  48. 48. Two Apache Processes Read/Write Remove all extra modules SSL Secondary server, Authenticated running as user dav File System, owned by dav48
  49. 49. Multi-server config. drwxr-xr-x 2 dav dav 68 Oct 3 12:41 /var/www1Listen *:80User wwwGroup wwwDocumentRoot /var/www/ Listen *:8080 2 DavLockDb /var/lock/dav User dav Group dav DocumentRoot /var/www/49
  50. 50. drwxr-xr-x 2 dav dav 68 Oct 3 12:41 /var/www1Listen *:80 Can writeUser wwwGroup wwwDocumentRoot /var/www/ Listen *:8080 2 DavLockDb /var/lock/dav User dav Group dav DocumentRoot /var/www/50
  51. 51. drwxr-xr-x 2 dav dav 68 Oct 3 12:41 /var/www1 Can’tListen *:80User wwwGroup wwwDocumentRoot /var/www/ Listen *:8080 2 DavLockDb /var/lock/dav User dav Group dav DocumentRoot /var/www/51
  52. 52. <If> Picture by BrewBooks (Flickr) My favorite new feature in 2.4
  53. 53. <If> <If ‘$req{Host} = “www.example.com”’> RedirectMatch (.*) http://example.com/$1 </If>
  54. 54. <If> <If ‘$req{Host} = “www.example.com”’> RedirectMatch (.*) http://example.com/$1 </If> This was hard prior to 2.4, and probably required mod_rewrite, or a separate virtual host.
  55. 55. <If> <If ‘$req{Host} = “www.example.com”’> RedirectMatch (.*) http://example.com/$1 </If> $req $resp $env
  56. 56. Logging in 2.4 FYI: • 2.4 is currently in beta • Will release any day now • 2.0 will be declared "end of life" • 2.2 will be declared "maintenance only"
  57. 57. Per-module LogLevel • mod_proxy is very chatty • I really want to know what mod_substitute is doing • Each log line prefixed by the name of the module LogLevel warning substitute:debug
  58. 58. [Mon Aug 29 08:05:02.001881 2011] [core:warn] [pid 14974:tid140735307352416] pid file /usr/local/apache2/logs/httpd.pid overwritten --Unclean shutdown of previous Apache run?[Mon Aug 29 08:05:02.009024 2011] [mpm_event:notice] [pid 14974:tid140735307352416] Apache/2.3.12-dev (Unix) PHP/5.3.6 DAV/2 configured-- resuming normal operations[Mon Aug 29 08:05:02.009411 2011] [core:notice] [pid 14974:tid140735307352416] Command line: /usr/local/apache2/bin/httpd[Mon Aug 29 08:05:16.479215 2011] [negotiation:error] [pid 14977:tid4322246656] (2)No such file or directory: [client ::1:54690] cannot accesstype map file: /Users/rbowen/devel/apache/httpd-trunk/docs/manual/logging.html
  59. 59. LogLevel settings • emerg • alert • crit • error • warn • notice • info • debug
  60. 60. New ones:
  61. 61. LogLevels • Original LogLevel settings taken from syslog • New ones more simply named tracen • Noisier than debug • Not to be confused with TRACEEnable, which is something completely different
  62. 62. No more RewriteLog LogLevel alert rewrite:trace3 • Trace slows things down - use only for debugging • tail -f error_log | grep "rewrite:"
  63. 63. Configurable • Error log format is configurable, like the access log ErrorLogFormat "[%t] [%l] [pid %P] %F: %E: [client %a] %M"
  64. 64. [Sun Sep 04 18:30:47.846743 2011] [rewrite:trace1] [pid15332:tid 4334051328] mod_rewrite.c(468): [client ::1:61990] ::1 - - [localhost/sid#10080f190][rid#10286b2a0/initial] pass through /favicon.ico[Sun Sep 04 18:30:47.850033 2011] [core:error] [pid15332:tid 4334051328] [client ::1:61990] File does not exist: /usr/local/apache2/htdocs/favicon.ico
  65. 65. Whodunnit? (%L) • Correlate access log entries with error log entries • Which request caused this error? • Add %L to the LogFormat and to the ErrorLogFormat
  66. 66. FallbackResource# BEGIN WordPress  RewriteEngine On  RewriteRule ^index.php$ - [L]  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d  RewriteRule . /index.php [L]# END WordPress
  67. 67. FallbackResource# BEGIN WordPress#  RewriteEngine On# RewriteRule ^index.php$ - [L]# RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f#  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d#  RewriteRule . /index.php [L]# END WordPressFallbackResource /index.php# available in 2.2.8
  68. 68. Logging - Conditional Logging • Don’t log certain things • Per-directory logging68
  69. 69. Conditional LogFormat • The LogFormat directive supports some conditionals in the variables • "%!200,304,302{Referer}i" logs Referer on all requests that do not return one of the three specified codes69
  70. 70. Conditional LogFormat • "%400,501{User-agent}i" logs User-agent on 400 errors and 501 errors only • For other status codes, the literal string "-" will be logged70
  71. 71. Conditional CustomLog • Stick Env=xyz on the end • or Env=!xyz • Yes, that’s =! not !=71
  72. 72. For example ...SetEnvIf Request_URI .gif$ gif-imageCustomLog gif-requests.log common env=gif-imageCustomLog nongif-requests.log common env=!gif-image 72
  73. 73. For example ...SetEnvIf Request_URI .gif$ gif-imageCustomLog gif-requests.log common env=gif-imageCustomLog nongif-requests.log common env=!gif-image 73
  74. 74. For example ...SetEnvIf Request_URI .gif$ gif-imageCustomLog gif-requests.log common env=gif-imageCustomLog nongif-requests.log common env=!gif-image 74
  75. 75. So the images get logged hereSetEnvIf Request_URI .gif$ gif-imageCustomLog gif-requests.log common env=gif-imageCustomLog nongif-requests.log common env=!gif-image 75
  76. 76. And everything else goes hereSetEnvIf Request_URI .gif$ gif-imageCustomLog gif-requests.log common env=gif-imageCustomLog nongif-requests.log common env=!gif-image 76
  77. 77. Per directorySetEnvIf Request_URI ^/marketing mktCustomLog marketing.log common env=mkt 77
  78. 78. PCRE Zero-width assertions • Match everything except one thing • While you can do this with RewriteRule, it would be nice if you could do it with other directives DirectoryMatch FilesMatch RedirectMatch
  79. 79. Negative Lookahead • PCRE provides a regex syntax to say “not preceded by” or “not followed by” • Negative lookbehind and negative lookahead, respectively
  80. 80. Andrei Rocks • While we’re on the topic: • Pretty much the best presentation on regular expressions anywhere: • http://www.slideshare.net/ andreizm/andreis-regex-clinic
  81. 81. Everything except ... • “I want to redirect everything except / images” • This is where you’d use a negative lookahead • Necessary because RedirectMatch doesn’t support negation RedirectMatch ^/(?!images/)(.*) http://other.myhost.com/$1
  82. 82. Everything except ... • Match anything ... • RedirectMatch ^/(?!images/)(.*) http://other.myhost.com/$1
  83. 83. Everything except ... • Match anything ... • That doesn’t start with images/ RedirectMatch ^/(?!images/)(.*) http://other.myhost.com/$1
  84. 84. Everything except ... This is called a “zero width” assertion, because it doesn’t fill $1, and doesn’t consume any characters in the match. RedirectMatch ^/(?!images/)(.*) http://other.myhost.com/$1
  85. 85. What the heck is it doing? RewriteLog /var/log/rewrite.log RewriteLogLevel 9
  86. 86. What the heck is it doing? RewriteLog /var/log/rewrite.log RewriteLogLevel 9 • Alas, not in .htaccess • Logs are always opened at startup
  87. 87. What the heck is it doing? RewriteLog /var/log/rewrite.log RewriteLogLevel 9 • Most entries between 1-4
  88. 88. What the heck is it doing? RewriteLog /var/log/rewrite.log RewriteLogLevel 9 • If there’s nothing in there, your rules are being ignored.
  89. 89. Logging - RewriteLog RewriteLog /var/log/rewrite.log RewriteLogLevel 990
  90. 90. Logging - RewriteLog RewriteLog /var/log/rewrite.log RewriteLogLevel 991
  91. 91. Logging - RewriteLog RewriteLog /var/log/rewrite.log RewriteLogLevel 992
  92. 92. 93
  93. 93. Kind of intimidating, isn’t it?94
  94. 94. Learn to ignore the irrelevant bits95
  95. 95. Which bits are those? 121.14.76.185 - - [24/Sep/2008:21:35:51 --0400] [wooga.drbacchus.com/sid#b83444a8][rid#b85b8d00/ initial] (4) [perdir /var/www/vhosts/drbacchus/] RewriteCond: input=/var/www/vhosts/drbacchus/ podcasts/poetry/maninmoon.mp3 pattern=!-f => not- matched96
  96. 96. Client address 121.14.76.185 - - [24/Sep/2008:21:35:51 --0400] [wooga.drbacchus.com/sid#b83444a8][rid#b85b8d00/ initial] (4) [perdir /var/www/vhosts/drbacchus/] RewriteCond: input=/var/www/vhosts/drbacchus/ podcasts/poetry/maninmoon.mp3 pattern=!-f => not- matched97
  97. 97. Dunno what those are 121.14.76.185 - - [24/Sep/2008:21:35:51 --0400] [wooga.drbacchus.com/sid#b83444a8][rid#b85b8d00/ initial] (4) [perdir /var/www/vhosts/drbacchus/] RewriteCond: input=/var/www/vhosts/drbacchus/ podcasts/poetry/maninmoon.mp3 pattern=!-f => not- matched98
  98. 98. Time 121.14.76.185 - - [24/Sep/2008:21:35:51 --0400] [wooga.drbacchus.com/sid#b83444a8][rid#b85b8d00/ initial] (4) [perdir /var/www/vhosts/drbacchus/] RewriteCond: input=/var/www/vhosts/drbacchus/ podcasts/poetry/maninmoon.mp3 pattern=!-f => not- matched99
  99. 99. Unique id 121.14.76.185 - - [24/Sep/2008:21:35:51 --0400] [wooga.drbacchus.com/sid#b83444a8][rid#b85b8d00/ initial] (4) [perdir /var/www/vhosts/drbacchus/] RewriteCond: input=/var/www/vhosts/drbacchus/ podcasts/poetry/maninmoon.mp3 pattern=!-f => not- matched100
  100. 100. Request ID 121.14.76.185 - - [24/Sep/2008:21:35:51 --0400] [wooga.drbacchus.com/sid#b83444a8][rid#b85b8d00/ initial] (4) [perdir /var/www/vhosts/drbacchus/] RewriteCond: input=/var/www/vhosts/drbacchus/ podcasts/poetry/maninmoon.mp3 pattern=!-f => not- matched101
  101. 101. The useful bit 121.14.76.185 - - [24/Sep/2008:21:35:51 --0400] [wooga.drbacchus.com/sid#b83444a8][rid#b85b8d00/ initial] (4) [perdir /var/www/vhosts/drbacchus/] RewriteCond: input=/var/www/vhosts/drbacchus/ podcasts/poetry/maninmoon.mp3 pattern=!-f => not- matched102
  102. 102. Wouldn’t it be nice if you could just see the useful part?103
  103. 103. You could change the way mod_rewrite logs:
  104. 104. Piped logs • I actually use a piped lot handler to remove this superfluous stuff • Like so ...RewriteLog |/usr/local/bin/rewrite_log_pipeRewriteLogLevel 9105
  105. 105. RewriteLog |/usr/local/bin/rewrite_log_pipe RewriteLogLevel 9 with ... #!/usr/bin/perl $|++; open (F, ">>/tmp/rewrite"); select F; while (<>) { s/^.*((d).*)/$1/; print; }106
  106. 106. RewriteLog |/usr/local/bin/rewrite_log_pipe RewriteLogLevel 9 This bit says “instead of logging to a text file, invoke this script and send the log entries there.”107
  107. 107. #!/usr/bin/perl $|++; open (F, ">>/tmp/rewrite"); select F; while (<>) { s/^.*((d).*)/$1/; print; } • Look for the (1) or (2) bit • drop everything before that108
  108. 108. Results in: (4) RewriteCond: input=wooga.drbacchus.com pattern=!^wooga.drbacchus .com [NC] => not-matched (3) applying pattern wp-rss2.php to uri /index.php (3) applying pattern (journal/)?index.rdf to uri /index.php (3) applying pattern ^/wordpress/wp-comments to uri /index.php (3) applying pattern ^/perm/(.*) to uri /index.php (3) applying pattern ^/articles?/(.*) to uri /index.php (3) applying pattern ^/blog/(.*) to uri /index.php (3) applying pattern ^/book/(mod)?_?rewrite to uri /index.php (3) applying pattern ^/book/cookbook to uri /index.php (3) applying pattern ^/book/2.2 to uri /index.php (3) applying pattern ^/booklink/(.*) to uri /index.php (3) applying pattern ^/books?/(.+) to uri /index.php (1) pass through /index.php109
  109. 109. Results in: (4) RewriteCond: input=wooga.drbacchus.com pattern=!^wooga.drbacchus .com [NC] => not-matched (3) applying pattern wp-rss2.php to uri /index.php (3) applying pattern (journal/)?index.rdf to uri /index.php (3) applying pattern ^/wordpress/wp-comments to uri /index.php (3) applying pattern ^/perm/(.*) to uri /index.php (3) applying pattern ^/articles?/(.*) to uri /index.php (3) applying pattern ^/blog/(.*) to uri /index.php better? See? Isn’t that (3) applying pattern ^/book/(mod)?_?rewrite to uri /index.php (3) applying pattern ^/book/cookbook to uri /index.php (3) applying pattern ^/book/2.2 to uri /index.php (3) applying pattern ^/booklink/(.*) to uri /index.php (3) applying pattern ^/books?/(.+) to uri /index.php (1) pass through /index.php110
  110. 110. Requested URI (4) RewriteCond: input=wooga.drbacchus.com pattern=!^wooga.drbacchus .com [NC] => not-matched (3) applying pattern wp-rss2.php to uri /index.php (3) applying pattern (journal/)?index.rdf to uri /index.php (3) applying pattern ^/wordpress/wp-comments to uri /index.php (3) applying pattern ^/perm/(.*) to uri /index.php (3) applying pattern ^/articles?/(.*) to uri /index.php (3) applying pattern ^/blog/(.*) to uri /index.php (3) applying pattern ^/book/(mod)?_?rewrite to uri /index.php (3) applying pattern ^/book/cookbook to uri /index.php (3) applying pattern ^/book/2.2 to uri /index.php (3) applying pattern ^/booklink/(.*) to uri /index.php (3) applying pattern ^/books?/(.+) to uri /index.php (1) pass through /index.php111
  111. 111. Patterns applied (4) RewriteCond: input=wooga.drbacchus.com pattern=!^wooga.drbacchus .com [NC] => not-matched (3) applying pattern wp-rss2.php to uri /index.php (3) applying pattern (journal/)?index.rdf to uri /index.php (3) applying pattern ^/wordpress/wp-comments to uri /index.php (3) applying pattern ^/perm/(.*) to uri /index.php (3) applying pattern ^/articles?/(.*) to uri /index.php (3) applying pattern ^/blog/(.*) to uri /index.php (3) applying pattern ^/book/(mod)?_?rewrite to uri /index.php (3) applying pattern ^/book/cookbook to uri /index.php (3) applying pattern ^/book/2.2 to uri /index.php (3) applying pattern ^/booklink/(.*) to uri /index.php (3) applying pattern ^/books?/(.+) to uri /index.php (1) pass through /index.php112
  112. 112. None of them matched (4) RewriteCond: input=wooga.drbacchus.com pattern=!^wooga.drbacchus .com [NC] => not-matched (3) applying pattern wp-rss2.php to uri /index.php (3) applying pattern (journal/)?index.rdf to uri /index.php (3) applying pattern ^/wordpress/wp-comments to uri /index.php (3) applying pattern ^/perm/(.*) to uri /index.php (3) applying pattern ^/articles?/(.*) to uri /index.php (3) applying pattern ^/blog/(.*) to uri /index.php (3) applying pattern ^/book/(mod)?_?rewrite to uri /index.php (3) applying pattern ^/book/cookbook to uri /index.php (3) applying pattern ^/book/2.2 to uri /index.php (3) applying pattern ^/booklink/(.*) to uri /index.php (3) applying pattern ^/books?/(.+) to uri /index.php (1) pass through /index.php113
  113. 113. And now • We can actually make some sense of what’s happening • Less inscrutable noise • Yes, it means something, but not to normal people114
  114. 114. Examples (4) RewriteCond: input=wooga.drbacchus.com pattern=!^wooga.drbacchus .com [NC] => not-matched • This was the result of RewriteCond %{HTTP_HOST} !^wooga.drbacchus.com [NC]115
  115. 115. Examples (4) RewriteCond: input=wooga.drbacchus.com pattern=!^wooga.drbacchus .com [NC] => not-matched • It shows what the input variable looked like RewriteCond %{HTTP_HOST} !^wooga.drbacchus.com [NC]116
  116. 116. Examples (4) RewriteCond: input=wooga.drbacchus.com pattern=!^wooga.drbacchus .com [NC] => not-matched • And what pattern was applied RewriteCond %{HTTP_HOST} !^wooga.drbacchus.com [NC]117
  117. 117. Examples (4) RewriteCond: input=wooga.drbacchus.com pattern=!^wooga.drbacchus .com [NC] => not-matched • As well as what happened RewriteCond %{HTTP_HOST} !^wooga.drbacchus.com [NC]118
  118. 118. Another example (3) applying pattern ^/book/(mod)?_?rewrite to uri / index.php • Was a result of RewriteRule ^/book/(mod)?_?rewrite http://www.amazon.com/exec/obidos/asin/ 1590595610/drbacchus/ [R,L]119
  119. 119. Again ... (3) applying pattern ^/book/(mod)?_?rewrite to uri / index.php • What was requested RewriteRule ^/book/(mod)?_?rewrite http://www.amazon.com/exec/obidos/asin/ 1590595610/drbacchus/ [R,L]120
  120. 120. And ... (3) applying pattern ^/book/(mod)?_?rewrite to uri / index.php • What it was compared against RewriteRule ^/book/(mod)?_?rewrite http://www.amazon.com/exec/obidos/asin/ 1590595610/drbacchus/ [R,L]121
  121. 121. Matched? (3) applying pattern ^/book/(mod)?_?rewrite to uri / index.php • If it matched, the next line will be the action log RewriteRule ^/book/(mod)?_?rewrite http://www.amazon.com/exec/obidos/asin/ 1590595610/drbacchus/ [R,L]122
  122. 122. The whole thing(3) applying pattern ^/books?/(mod)?_?rewrite to uri /books/rewrite(2) rewrite /books/rewrite -> http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/(2) explicitly forcing redirect with http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/(1) escaping http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/ for redirect(1) redirect to http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/ [REDIRECT/302]123
  123. 123. The match:(3) applying pattern ^/books?/(mod)?_?rewrite to uri /books/rewrite(2) rewrite /books/rewrite -> http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/(2) explicitly forcing redirect with http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/(1) escaping http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/ for redirect(1) redirect to http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/ [REDIRECT/302]124
  124. 124. Followed by(3) applying pattern ^/books?/(mod)?_?rewrite to uri /books/rewrite(2) rewrite /books/rewrite -> http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/(2) explicitly forcing redirect with http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/(1) escaping http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/ for redirect(1) redirect to http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/ [REDIRECT/302]125
  125. 125. [R](3) applying pattern ^/books?/(mod)?_?rewrite to uri /books/rewrite(2) rewrite /books/rewrite -> http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/(2) explicitly forcing redirect with http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/(1) escaping http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/ for redirect(1) redirect to http://www.amazon.com/exec/obidos/asin/1590595610/drbacchus/ [REDIRECT/302]126
  126. 126. But it all runs together! • Look for: • (2) init rewrite engine with requested uri /atom/1 • ‘init rewrite engine’ shows where a new request started being rewritten127
  127. 127. Load balancing
  128. 128. Fortunately ... Photo CC by Camo53 (flickr) • mod_proxy_balancer • Added in 2.1
  129. 129. Fairly simple to configure <Proxy balancer://mycluster> BalancerMember http://192.168.1.50:80 BalancerMember http://192.168.1.51:80 </Proxy> ProxyPass /test balancer://mycluster
  130. 130. Fairly simple to configure <Proxy balancer://mycluster> BalancerMember http://192.168.1.50:80 BalancerMember http://192.168.1.51:80 </Proxy> ProxyPass /test balancer://mycluster
  131. 131. Fairly simple to configure <Proxy balancer://mycluster> BalancerMember http://192.168.1.50:80 BalancerMember http://192.168.1.51:80 </Proxy> ProxyPass /test balancer://mycluster
  132. 132. Sticky Sessions Ensures that connections go to the same server they started with.ProxyPass / balancer://mycluster/ stickysession=PHPSESSIONID135
  133. 133. Balancing measures ProxyPass / balancer://hotcluster/ <Proxy balancer://hotcluster> BalancerMember http://1.2.3.4:8009 loadfactor=1 BalancerMember http://1.2.3.5:8009 loadfactor=2 # The below is the hot standby BalancerMember http://1.2.3.6:8009 status=+H ProxySet lbmethod=bytraffic </Proxy>136
  134. 134. 1.2.3.5 gets twice the traffic ProxyPass / balancer://hotcluster/ <Proxy balancer://hotcluster> BalancerMember http://1.2.3.4:8009 loadfactor=1 BalancerMember http://1.2.3.5:8009 loadfactor=2 # The below is the hot standby BalancerMember http://1.2.3.6:8009 status=+H ProxySet lbmethod=bytraffic </Proxy>137
  135. 135. Hot spare ProxyPass / balancer://hotcluster/ <Proxy balancer://hotcluster> BalancerMember http://1.2.3.4:8009 loadfactor=1 BalancerMember http://1.2.3.5:8009 loadfactor=2 # The below is the hot standby BalancerMember http://1.2.3.6:8009 status=+H ProxySet lbmethod=bytraffic </Proxy>138
  136. 136. bytraffic or byrequests ProxyPass / balancer://hotcluster/ <Proxy balancer://hotcluster> BalancerMember http://1.2.3.4:8009 loadfactor=1 BalancerMember http://1.2.3.5:8009 loadfactor=2 # The below is the hot standby BalancerMember http://1.2.3.6:8009 status=+H ProxySet lbmethod=bytraffic </Proxy>139
  137. 137. BalancerManager <Location /balancer-manager> SetHandler balancer-manager Order Deny,Allow Deny from all Allow from .example.com </Location>140
  138. 138. 141
  139. 139. Disable a particular host142
  140. 140. Notes • The things on the other end don’t have to be Apache • This is a popular way to set up Ruby on Rails, with Mongrel143
  141. 141. server-info <Location /server-info> SetHandler server-info </Location>
  142. 142. Demo • Insert /server-info demo here
  143. 143. Require • Order deny,allow • Order allow,deny • huh?
  144. 144. Require
  145. 145. Require
  146. 146. RequireAll <RequireAll> Require ip 10.1 Require Group marketing </RequireAll>
  147. 147. RequireAny <RequireAny> Require ip 10.1 Require Group marketing </RequireAny>
  148. 148. RequireNone <RequireNone> Require ip 10.1 Require Group marketing </RequireNone>
  149. 149. Combined <Directory /www/mydocs> <RequireAll> <RequireAny> Require user superadmin <RequireAll> Require group admins Require ldap-group cn=Administrators,o=Airius <RequireAny> Require group sales Require ldap-attribute dept="sales" </RequireAny> </RequireAll> </RequireAny> <RequireNone> Require group temps Require ldap-group cn=Temporary Employees,o=Airius </RequireNone> </RequireAll> </Directory>
  150. 150. Expressions • New expression parser in 2.4 • Available in most directives that do any kind of comparison or matching • Will be available more places as time goes on
  151. 151. Other ... • http://localhost/manual/expr.html
  152. 152. Bandwidth limiting Picture by Joachim S. Müller (Flickr) People always want their websites to run slower. Seems odd to me ...
  153. 153. In 2.4 ... • 2.4 adds two new modules for this purpose • mod_dialup • mod_ratelimit
  154. 154. mod_dialup Party like it’s 1999
  155. 155. v.92? Really? <Location /mysite> ModemStandard V.92 </Location> Also available: V.21 V.26bis V.32 V.92
  156. 156. mod_ratelimit <Location /downloads> SetHandler RATE_LIMIT SetEnv rate-limit 400 </Location> Speed is in kb/s
  157. 157. Prior to 2.4 A variety of other modules do bandwidth kind of things: mod_cband mod_bwshare mod_bw mod_evasive mod_limitipconn
  158. 158. Logging • mod_logio • mod_log_forensic
  159. 159. Obligatory ridiculous log photo Photo by Zevotron (Flickr)
  160. 160. Not enough • Your log files don’t tell you enough • Want more
  161. 161. Logging - mod_logio Complete INPUT and OUTPUT size170
  162. 162. Logging - mod_logio Complete INPUT and OUTPUT size171
  163. 163. Combined Log Format - Bytes transferred172
  164. 164. Less than half the story • Only bytes transferred to the client • Doesn’t include headers • Doesn’t include data sent from the client to the server173
  165. 165. mod_logio •Adds two additional variables •%I - Input bytes •%O - Output bytes •Includes headers, both directions174
  166. 166. LogFormat175
  167. 167. mod_log_forensic • Did it ever finish?
  168. 168. ForensicLog ForensicLog /var/log/httpd/forensic.log+TlvWvsCoyKYAAAPmBy8AAABG|GET /manual/images/feather.gif HTTP/1.1|Host:localhost|Connection:keep-alive|Referer:http%3a//localhost/manual/|User-Agent:Mozilla/5.0 (Macintosh; IntelMac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1|Accept:*/*|Accept-Encoding:gzip,deflate,sdch|Accept-Language:en-US,en;q=0.8,de;q=0.6|Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3+TlvWvsCoyKYAAAPmBzAAAABB|GET /manual/style/css/manual.css HTTP/1.1|Host:localhost|Connection:keep-alive|Referer:http%3a//localhost/manual/|User-Agent:Mozilla/5.0 (Macintosh; IntelMac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1|Accept:text/css,*/*;q=0.1|Accept-Encoding:gzip,deflate,sdch|Accept-Language:en-US,en;q=0.8,de;q=0.6|Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3+TlvWvsCoyKYAAAPmBzEAAABI|GET /manual/images/left.gif HTTP/1.1|Host:localhost|Connection:keep-alive|Referer:http%3a//localhost/manual/|User-Agent:Mozilla/5.0 (Macintosh; IntelMac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1|Accept:*/*|Accept-Encoding:gzip,deflate,sdch|Accept-Language:en-US,en;q=0.8,de;q=0.6|Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3-TlvWvsCoyKYAAAPmBy8AAABG-TlvWvsCoyKYAAAPmBzAAAABB-TlvWvsCoyKYAAAPmBzEAAABI
  169. 169. ForensicLog ForensicLog /var/log/httpd/forensic.log • Post-process with the check- forensic script to tell you which URLs never exited
  170. 170. mod_whatkilledus • Third-party module • people.apache.org/~trawick/ Find it at http:// • Tells you what killed us
  171. 171. mod_whatkilledus[Fri Mar 11 14:25:18 2005] pid 16934 mod_whatkilledussig 11 crash[Fri Mar 11 14:25:18 2005] pid 16934 mod_whatkilledusactive connection: 127.0.0.1:43923->127.0.0.1:10101(conn_rec 30683a38)[Fri Mar 11 14:25:18 2005] pid 16934 mod_whatkilledusactive request (request_rec 30689978):GET /silly/?fn=sigsegv HTTP/1.0|Connection:close[Fri Mar 11 14:25:18 2005] pid 16934 mod_whatkilledusActive module: mod_silly2.c[Fri Mar 11 14:25:18 2005] pid 16934 mod_whatkilledusend of report
  172. 172. mod_speling CheckSpelling On CheckCaseOnly On
  173. 173. Image Theft • <img src="http://your.site.com/ cool_picture.jpg">
  174. 174. Image Theft SetEnvIf Referer ".example.com/" local_referal # Allow browsers that do not send Referer info SetEnvIf Referer "^$" local_referal <Directory /web/images> Order Deny,Allow Deny from all Allow from env=local_referal </Directory>
  175. 175. Or ...RewriteEngine onRewriteCond %{HTTP_REFERER} !=""RewriteCond %{HTTP_REFERER} !example.com [NC]RewriteRule .(jpe?g|gif|png)$ - [F,NC]
  176. 176. Or ...RewriteEngine onRewriteCond %{HTTP_REFERER} !=""RewriteCond %{HTTP_REFERER} !example.com [NC]# depending upon in which context# you use the RewriteRule,# you might need a condition to# exclude the go_away.png to prevent# an internal redirect looping. We dont use a RegEx here:RewriteCond %{REQUEST_URI} !=/images/go_away.pngRewriteRule .(jpe?g|gif|png)$ /images/go_away.png [NC,L]
  177. 177. Or ...RewriteEngine onRewriteCond %{HTTP_REFERER} !=""RewriteCond %{HTTP_REFERER} !example.com [NC]# depending upon in which context# you use the RewriteRule,# you might need a condition to# exclude the go_away.png to prevent# an internal redirect looping. We dont use a RegEx here:RewriteCond %{REQUEST_URI} !=/images/go_away.pngRewriteRule .(jpe?g|gif|png)$ http://other.example.com/images/go_away.png [R,NC,L]
  178. 178. Or ... In 2.4:<Location /images> <If "$req{Referer} !~ /mysite.com/"> Require all denied </If></Location>
  179. 179. Query Strings and Path Info
  180. 180. Query Stringsmonkeys.php?q=lemur&color=green&level=99.7&doc=info.txt • Query Strings are: • Ugly • Hard to type • Hard to remember • Potentially insecure
  181. 181. Query Stringsmonkeys.php?q=lemur&color=green&level=99.7&doc=info.txt • Query Strings are: • Ugly • Hard to type • Hard to remember • Potentially insecure
  182. 182. Path Infomonkeys.php?q=lemur&color=green&level=99.7&doc=info.txt /monkeys/lemur/green/99.7/info
  183. 183. mod_rewritemonkeys.php?q=lemur&color=green&level=99.7&doc=info.txt /monkeys/lemur/green/99.7/info RewriteRule ^/monkeys/(.+)/(.+)/(.+)/(.+) /monkeys.php?q=$1&color=$2&level=$3&doc=$4.txt [PT,L,NE]
  184. 184. Engineering for failure • Why not do it right to begin with, and avoid the mess? • PHP makes this fairly easy • Use exactly the same technique in whatever your preferred language is
  185. 185. Step One: SetHandler /monkeys/lemur/green/99.7/info • We want monkeys to be a PHP script • We rename monkeys.php to monkeys, and then ... <Files monkeys> SetHandler application/x-httpd-php </Files> This goes in your server config, or in .htaccess
  186. 186. Step Two: explode() /monkeys/lemur/green/99.7/info • The rest of the solution is in your PHP: $args = explode( $_SERVER[‘PATH_INFO’] ); $type = $args[0]; $color = $args[1]; ...
  187. 187. While we’re at it • File extensions are *so* 1980s • All your files are php files, right? • Why give them a .php extension? RewriteCond %{REQUEST_URI} !. RewriteRule ^ - [H=application/x-httpd-php,PT]
  188. 188. ... • If, by some miracle, we get this far ... • Questions?
  189. 189. Addresses you need • http://slideshare.net/rbowen • http://wiki.apache.org/httpd • http://httpd.apache.org/docs/trunk/ • rbowen@apache.org • http://omniti.com/is/hiring

×