在请求 URL 中公开表名和字段名
我的任务是创建这个 Joomla 组件(是的,joomla;但它无关),一位教授告诉我,我应该使我的代码尽可能动态(需要较少维护的代码)并避免硬编码。我们最初想到的方法是获取 url 参数,将它们转换为对象,然后将它们传递给查询。
假设我们要读取表“hotels”中 id # 1 的酒店。假设该表包含字段“hotel_id”、“hotel_name”和一些其他字段。
现在,我们制作 sql 查询字符串的方法是解析如下所示的 url 请求:
index.php?task=view&table=hotels&hotel_id=1¶m1=something¶m2=somethingelse
并将其转换为如下所示的 PHP 对象(以 JSON 等效形式显示,更易于理解):
obj = {
'table':'hotel',
'conditions':{
'hotel_id':'1',
'param1':'something',
'param2':'somethingelse'
}
SQL 查询将是这样的像这样,其中条件被循环并附加到字符串中,其中 WHERE 子句的字段和值是对象的键和值(为了方便起见,仍然采用 JSON 形式):
SELECT * FROM obj.table WHERE hotel_id=1 AND param1=something and so on...
困扰我的问题是表名和字段的暴露请求 URL 中的名称。我知道这会带来安全风险,暴露仅应在服务器端可见的项目。我正在考虑的当前解决方案是为客户端的每个表和字段提供别名 - 但这将是硬编码,这违反了他的政策。此外,如果我这样做,并且有一千个表要别名,那就不切实际了。
没有以下情况的正确方法是什么:
- 硬编码的东西
- 使代码保持动态和适应性
编辑:
关于任意查询(我忘记包括这一点),目前在后端阻止它们的是一个函数,它从硬编码对象(更像是此处显示的配置文件)获取引用,并通过挑选参数或匹配参数来解析 url。
配置如下所示:
// 'hotels' here is the table name. instead of parsing the url for a table name
// php will just find the table from this config. if no match, return error.
// reduces risk of arbitrary tables.
'hotels' => array(
// fields and their types, used to identify what filter to use
'structure' => array(
'hotel_id'=>'int',
'name'=>'string',
'description'=>'string',
'featured'=>'boolean',
'published'=>'boolean'
),
//these are the list of 'tasks' and accepted parameters, based on the ones above
//these are the actual parameter names which i said were the same as field names
//the ones in 'values' are usually values for inserting and updating
//the ones in 'conditions' are the ones used in the WHERE part of the query
'operations' =>array(
'add' => array(
'values' => array('name','description','featured'),
'conditions' => array()
),
'view' => array(
'values' => array(),
'conditions' => array('hotel_id')
),
'edit' => array(
'values' => array('name','description','featured'),
'conditions' => array('hotel_id')
),
'remove' => array(
'values' => array(),
'conditions' => array('hotel_id')
)
)
)
因此,从该配置列表来看:
- 如果为任务发送的参数不完整,服务器将返回错误。
- 如果 url 中的参数加倍,则仅采用读取的第一个参数。
- 配置中不存在的任何其他参数都将被丢弃
- 如果不允许该任务,则
- ,如果任务不存在,则不会为该表列出它,如果表不存在,服务器返回错误
- ,服务器返回错误
我实际上在之后对此进行了模式化在 joomla 中看到一个使用此策略的组件。它将模型和控制器减少到 4 个动态函数,这将是 CRUD,只留下配置文件作为以后唯一可编辑的文件(这就是我关于动态代码的意思,如果需要更多表,我只添加表和任务)但我担心这可能会带来我可能还不知道的安全风险。
有什么替代方案吗?
I was tasked to create this Joomla component (yep, joomla; but its unrelated) and a professor told me that I should make my code as dynamic as possible (a code that needs less maintenance) and avoid hard coding. The approach we thought initially is take url parameters, turn them into objects, and pass them to query.
Let's say we want to read hotel with id # 1 in the table "hotels". lets say the table has the fields "hotel_id", "hotel_name" and some other fields.
Now, the approach we took in making the sql query string is to parse the url request that looked like this:
index.php?task=view&table=hotels&hotel_id=1¶m1=something¶m2=somethingelse
and turned it into a PHP object like this (shown in JSON equivalent, easier to understand):
obj = {
'table':'hotel',
'conditions':{
'hotel_id':'1',
'param1':'something',
'param2':'somethingelse'
}
and the SQL query will be something like this where conditions are looped and appended into the string where field and value of the WHERE clause are the key and value of the object (still in JSON form for ease):
SELECT * FROM obj.table WHERE hotel_id=1 AND param1=something and so on...
The problem that bugged me was the exposing of the table name and field names in the request url. I know it poses a security risk exposing items that should only be seen to the server side. The current solution I'm thinking is giving aliases to each and every table and field for the client side - but that would be hard coding, which is against his policy. and besides, if I did that, and had a thousand tables to alias, it would not be practical.
What is the proper method to do this without:
- hard coding stuff
- keep the code as dynamic and adaptable
EDIT:
Regarding the arbitrary queries (I forgot to include this), what currently stops them in the back end is a function, that takes a reference from a hard-coded object (more like a config file shown here), and parses the url by picking out parameters or matching them.
The config looks like:
// 'hotels' here is the table name. instead of parsing the url for a table name
// php will just find the table from this config. if no match, return error.
// reduces risk of arbitrary tables.
'hotels' => array(
// fields and their types, used to identify what filter to use
'structure' => array(
'hotel_id'=>'int',
'name'=>'string',
'description'=>'string',
'featured'=>'boolean',
'published'=>'boolean'
),
//these are the list of 'tasks' and accepted parameters, based on the ones above
//these are the actual parameter names which i said were the same as field names
//the ones in 'values' are usually values for inserting and updating
//the ones in 'conditions' are the ones used in the WHERE part of the query
'operations' =>array(
'add' => array(
'values' => array('name','description','featured'),
'conditions' => array()
),
'view' => array(
'values' => array(),
'conditions' => array('hotel_id')
),
'edit' => array(
'values' => array('name','description','featured'),
'conditions' => array('hotel_id')
),
'remove' => array(
'values' => array(),
'conditions' => array('hotel_id')
)
)
)
and so, from that config list:
- if a parameters sent for a task is not complete, server returns an error.
- if a parameter from the url is doubled, only the first parameter read is taken.
- any other parameters not in the config are discarded
- if that task is not allowed, it wont be listed for that table
- if a task is not there, server returns an error
- if a table is not there, server returns an error
I actually patterned this after seeing a component in joomla that uses this strategy. It reduces the model and controller to 4 dynamic functions which would be CRUD, leaving only the config file to be the only file editable later on (this was what I meant about dynamic code, I only add tables and tasks if further tables are needed) but I fear it may impose a security risk which I may have not known yet.
Any ideas for an alternative?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我对在 URL 和数据库中使用相同(或非常相似)的名称没有任何问题 - 当然,您可能会“暴露”实现细节,但如果您在 URL 和数据库中选择完全不同的名称,那么您'我们可能会选择不好的名字。我也喜欢一致的命名——如果每个人对所有东西的称呼都略有不同,那么与编码人员/测试人员/客户的沟通就会变得更加困难。
让我烦恼的是你让用户在你的数据库上运行任意查询。
http://.../index.php?table=users&user_id=1
,比如说?或者http://.../index.php?table=users&password=password
(不是说您应该以明文形式存储密码)?或者http://.../index.php?table=users&age=11
?如果连接到数据库的用户与坐在 Web 浏览器前的用户具有相同的权限,那么这可能是有意义的。一般来说,情况并非如此,因此您需要一些层来了解用户是什么以及不允许查看什么,并且通过白名单该层更容易正确编写。
(如果您已将足够的逻辑放入存储过程中,那么它可能会起作用,但是您的存储过程将硬编码列名称......)
I have no problem with using the same (or very similar) names in the URL and the database — sure, you might be "exposing" implementation details, but if you're choosing radically different names in the URL and the DB, you're probably choosing bad names. I'm also a fan of consistent naming — communication with coders/testers/customers becomes much more difficult if everyone calls everything something slightly different.
What bugs me is that you're letting the user run arbitrary queries on your database.
http://.../index.php?table=users&user_id=1
, say? Orhttp://.../index.php?table=users&password=password
(not that you should be storing passwords in plaintext)? Orhttp://.../index.php?table=users&age=11
?If the user connected to the DB has the same permissions as the user sitting in front of the web browser, it might make sense. Generally, that's not going to be the case, so you'll need some layer that knows what the user is and isn't allowed to see, and that layer is a lot easier to write correctly by whitelisting.
(If you've stuck enough logic into stored procedures, then it might work, but then your stored procedures will hard-code column names...)
当使用输入数据编写 SQL 查询时,会带来安全风险。但请记住,列值是通过从用户处获取输入、对其进行分析并用其组成 SQL 查询(准备好的语句除外)来插入到字段中的。因此,如果操作正确,您无需担心 - 只需将用户限制在这些列和列表中即可。表。开源软件的代码/数据库对所有人都是可见的——而且它对系统的损害并不像人们想象的那么大。
When composing a SQL query with data from the input, it presents a security risk. But keep in mind that columns values are inserted to the fields by taking input from the user, analyzing it and composing a SQL query with it (except for prepared statements). So when done properly, you have nothing to worry about - simply restrict the user to those column & tables. Open source software's code/database is visible to all - and it doesn't harm the system so much as one would think.
您的别名可能是元/名称上的
rot13()
你的对象。不过,如果您在使用这些名称时相应地转义输入,我认为公开它们的名称不会有任何问题。
Your aliasses could be a
rot13()
on the meta/name of your objects.Although, if you escape the input accordingly when working with those names, I don't see any problem in exposing their names.