./../home/joeuser
to reference the same path, even though they are composed of different characters.
144 | Chapter 5: Security
You would need some form of path normalization if you wanted to compare these
paths. More importantly, you would want to know that /var/www/public/../config/
database.yml is most definitely not within /var/www/public, lest you try to serve it as
plain text to the client. As bad as that is, it is much worse when allowing a user to
upload files.
The double-dot problem (known as a directory traversal attack) is one of the oldest,
most basic canonicalization problems around, but it persists to this day. Path normalization
is easy in Ruby using the File.expand_path method, and this should
always be used as a final test for any files opened based on user input:
name = params[:filename]
base_path = File.expand_path(File.join(RAILS_ROOT, "public"))
file_path = File.join(base_path, name)
if File.expand_path(file_path).starts_with?(base_path)
data = File.read(file_path)
else
raise "Access denied"
end
Another approach to preventing directory traversal is to blacklist paths containing
characters such as ../. However, this is very, very hard to do right. Path components
can be URI-encoded, and it is difficult to predict how many levels of decoding
will be performed before hitting the filesystem. With the advent of Unicode and its
many encodings, there are myriad ways one set of characters can be represented to a
web application.
Pages:
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226