我的任务是创建这个Joomla组件(是的,joomla;但它无关),一位教授告诉我,我应该让我的代码尽可能动态(一个需要较少维护的代码)并避免硬编码。我们最初想到的方法是获取url参数,将它们转换为对象,然后将它们传递给查询。
假设我们想在“酒店”表中阅读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...
我遇到的问题是在请求网址中公开了表名和字段名。我知道这会产生安全风险,暴露出只应该向服务器端看到的项目。我正在考虑的当前解决方案是为客户端的每个表和字段提供别名 - 但这将是硬编码,这违反了他的政策。此外,如果我这样做,并且有一千个表别名,那就不实用了。
没有这样做的正确方法是什么:
修改
关于任意查询(我忘了包含这个),当前在后端停止它们的是一个函数,它从硬编码对象(更像是这里显示的配置文件)中引用,并解析通过挑选参数或匹配它们来获取网址。
配置如下:
// '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')
)
)
)
等等,从该配置列表:
在看到joomla中使用此策略的组件之后,我实际上对此进行了模式化。它将模型和控制器简化为4个动态函数,这些函数将是CRUD,只留下配置文件是以后唯一可编辑的文件(这就是我对动态代码的意思,如果需要更多的表,我只添加表和任务)但我担心它可能会带来安全风险,我可能还不知道。
任何替代方案的想法?
答案 0 :(得分:1)
使用输入中的数据编写SQL查询时,会带来安全风险。但请记住,通过从用户那里获取输入,分析它并使用它组成SQL查询(除了预准备语句),将列值插入到字段中。因此,如果操作正确,您无需担心 - 只需将用户限制为那些列&表。所有人都可以看到开源软件的代码/数据库 - 它不会像人们想象的那样损害系统。
答案 1 :(得分:1)
我在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浏览器前面的用户相同的权限,则可能有意义。通常,情况并非如此,因此您需要一些知道用户是什么并且不允许看到的图层,并且通过白名单更容易正确地编写该图层。
(如果你已经在存储过程中加入了足够的逻辑,那么它可能会有效,但是你的存储过程会对列名进行硬编码......)
答案 2 :(得分:0)
您的对象可能是对象元/名称的rot13()
。
虽然,如果在使用这些名称时相应地转义输入,我认为在公开其名称时没有任何问题。