Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/hgweb/common.py @ 31793:62f9679df1f2
hgweb: extract path traversal checking into standalone function
A common exploit in web applications that access paths is to insert
path separator strings like ".." to try to get the server to serve up
files it shouldn't.
We have code for detecting this in staticfile(). A subsequent commit
will need to perform this test as well. Since this is security code,
let's factor the check so we don't have to reinvent the wheel.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Fri, 31 Mar 2017 21:47:26 -0700 |
parents | 161a87ed456e |
children | d5b2beca16c0 |
comparison
equal
deleted
inserted
replaced
31792:161a87ed456e | 31793:62f9679df1f2 |
---|---|
133 return os.stat(spath) | 133 return os.stat(spath) |
134 | 134 |
135 def get_mtime(spath): | 135 def get_mtime(spath): |
136 return get_stat(spath, "00changelog.i").st_mtime | 136 return get_stat(spath, "00changelog.i").st_mtime |
137 | 137 |
138 def ispathsafe(path): | |
139 """Determine if a path is safe to use for filesystem access.""" | |
140 parts = path.split('/') | |
141 for part in parts: | |
142 if (part in ('', os.curdir, os.pardir) or | |
143 pycompat.ossep in part or | |
144 pycompat.osaltsep is not None and pycompat.osaltsep in part): | |
145 return False | |
146 | |
147 return True | |
148 | |
138 def staticfile(directory, fname, req): | 149 def staticfile(directory, fname, req): |
139 """return a file inside directory with guessed Content-Type header | 150 """return a file inside directory with guessed Content-Type header |
140 | 151 |
141 fname always uses '/' as directory separator and isn't allowed to | 152 fname always uses '/' as directory separator and isn't allowed to |
142 contain unusual path components. | 153 contain unusual path components. |
143 Content-Type is guessed using the mimetypes module. | 154 Content-Type is guessed using the mimetypes module. |
144 Return an empty string if fname is illegal or file not found. | 155 Return an empty string if fname is illegal or file not found. |
145 | 156 |
146 """ | 157 """ |
147 parts = fname.split('/') | 158 if not ispathsafe(fname): |
148 for part in parts: | 159 return |
149 if (part in ('', os.curdir, os.pardir) or | 160 |
150 pycompat.ossep in part or | 161 fpath = os.path.join(*fname.split('/')) |
151 pycompat.osaltsep is not None and pycompat.osaltsep in part): | |
152 return | |
153 fpath = os.path.join(*parts) | |
154 if isinstance(directory, str): | 162 if isinstance(directory, str): |
155 directory = [directory] | 163 directory = [directory] |
156 for d in directory: | 164 for d in directory: |
157 path = os.path.join(d, fpath) | 165 path = os.path.join(d, fpath) |
158 if os.path.exists(path): | 166 if os.path.exists(path): |