如何确定路径是否在目录内?(POSIX) [英] How to determine if a path is inside a directory? (POSIX)

查看:57
本文介绍了如何确定路径是否在目录内?(POSIX)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 C 中,使用 POSIX 调用,如何确定路径是否在目标目录内?

In C, using POSIX calls, how can I determine if a path is inside a target directory?

例如,Web 服务器的根目录在 /srv,这是守护进程的 getcwd().解析/index.html的请求时,返回/srv/index.html的内容.

For example, a web server has its root directory in /srv, this is getcwd() for the daemon. When parsing a request for /index.html, it returns the contents of /srv/index.html.

如何过滤对 /srv 之外的路径的请求?

How can I filter out requests for paths outside of /srv?

/../etc/passwd,/valid/../../etc/passwd,等

/ 处拆分路径并拒绝任何包含 .. 的数组将破坏有效访问 /srv/valid/../index.html.

Splitting the path at / and rejecting any array containing .. will break valid accesses /srv/valid/../index.html.

有没有一种规范的方法可以通过系统调用来做到这一点?还是我需要手动走路径并计算目录深度?

Is there a canonical way to do this with system calls? Or do I need to manually walk the path and count directory depth?

推荐答案

realpath:

realpath() 函数应从 *file_name* 指向的路径名派生出一个绝对路径名,该路径名解析为相同的目录条目,其解析不涉及 '.'、'..' 或符号链接.

The realpath() function shall derive, from the pathname pointed to by *file_name*, an absolute pathname that resolves to the same directory entry, whose resolution does not involve '.' , '..' , or symbolic links.

然后将 realpath 提供给您的内容与您想要的根目录进行比较,看看它们是否匹配.

Then compare what realpath gives you with your desired root directory and see if they match up.

您还可以通过在添加 "/srv" 之前扩展双点来手动清理文件名.用斜线分割传入路径并逐条穿过它.如果你得到一个 "." 然后将其删除并继续;如果你得到一个 "..",然后删除它和前一个组件(注意不要超过列表中的第一个条目);如果您有其他任何东西,请继续进行下一个组件.然后将剩下的内容与组件之间的斜线粘贴在一起,并在您的 "/srv/" 前面加上.所以如果有人给你 "/valid/../../etc/passwd",你最终会得到 "/srv/etc/passwd""/where/is/../pancakes/house" 最终会变成 "/srv/where/pancakes/house".

You could also clean up the filename by hand by expanding the double-dots before you prepend the "/srv". Split the incoming path on slashes and walk through it piece by piece. If you get a "." then remove it and move on; if you get a "..", then remove it and the previous component (taking care not go past the first entry in your list); if you get anything else, just move on to the next component. Then paste what's left back together with slashes between the components and prepend your "/srv/". So if someone gives you "/valid/../../etc/passwd", you'll end up with "/srv/etc/passwd" and "/where/is/../pancakes/house" will end up as "/srv/where/pancakes/house".

那样你就不能离开 "/srv"(当然通过符号链接除外),传入的 "/../.." 将是与 "/" 相同(就像在普通文件系统中一样).但是如果您担心 "/srv" 下的符号,您仍然希望使用 realpath.

That way you can't get outside "/srv" (except through symbolic links of course) and an incoming "/../.." will be the same as "/" (just like in a normal file system). But you'd still want to use realpath if you're worried about symbolic under "/srv".

逐个组件地使用路径名还可以让您打破呈现给外界的布局与实际文件系统布局之间的联系;"/this/that/other/thing" 不需要映射到实际的 "/srv/this/that/other/thing" 文件任何地方,路径可能只是某种数据库中的一个键或某种函数调用的命名空间路径.

Working with the path name component by component would also allow you to break the connection between the layout you present to the outside world and the actual file system layout; there's no need for "/this/that/other/thing" to map to an actual "/srv/this/that/other/thing" file anywhere, the path could just be a key in some sort of database or some sort of namespace path to a function call.

这篇关于如何确定路径是否在目录内?(POSIX)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆