Fix asset path-traversal outside of roots

Summary:`/assets/...` requests previously supported path-traversal potentially exposing and serving (private) files outside roots.

**Test plan**

Prior to patching perform the a path-traversal request to the server:
```
GET /assets/../../../../etc/hosts HTTP/1.1
Cache-Control: no-store
Host: 127.0.0.1:8081
Connection: close
Accept-Encoding: gzip
User-Agent: okhttp/2.5.0
```

Apply patch and verify a `404` response with body: `Asset not found`

Test normal asset requests work.
Closes https://github.com/facebook/react-native/pull/6398

Differential Revision: D3034857

Pulled By: shayne

fb-gh-sync-id: f0e6714e4e3c5a63a3a402634a1eb5f3186d3561
shipit-source-id: f0e6714e4e3c5a63a3a402634a1eb5f3186d3561
This commit is contained in:
Shayne Sweeney 2016-03-21 21:57:56 -07:00 committed by Facebook Github Bot 8
parent ebfb4f738a
commit 18612273be
1 changed files with 12 additions and 5 deletions

View File

@ -129,16 +129,23 @@ class AssetServer {
_findRoot(roots, dir) { _findRoot(roots, dir) {
return Promise.all( return Promise.all(
roots.map(root => { roots.map(root => {
const absPath = path.join(root, dir); // important: we want to resolve root + dir
// to ensure the requested path doesn't traverse beyond root
const absPath = path.resolve(root, dir);
return stat(absPath).then(fstat => { return stat(absPath).then(fstat => {
return {path: absPath, isDirectory: fstat.isDirectory()}; // keep asset requests from traversing files
}, err => { // up from the root (e.g. ../../../etc/hosts)
return {path: absPath, isDirectory: false}; if (!absPath.startsWith(root)) {
return {path: absPath, isValid: false};
}
return {path: absPath, isValid: fstat.isDirectory()};
}, _ => {
return {path: absPath, isValid: false};
}); });
}) })
).then(stats => { ).then(stats => {
for (let i = 0; i < stats.length; i++) { for (let i = 0; i < stats.length; i++) {
if (stats[i].isDirectory) { if (stats[i].isValid) {
return stats[i].path; return stats[i].path;
} }
} }