在请求URL中公开表名和字段名

时间:2011-07-24 14:47:04

标签: mysql security field client-side

我的任务是创建这个Joomla组件(是的,joomla;但它无关),一位教授告诉我,我应该让我的代码尽可能动态(一个需要较少维护的代码)并避免硬编码。我们最初想到的方法是获取url参数,将它们转换为对象,然后将它们传递给查询。

假设我们想在“酒店”表中阅读ID为#1的酒店。假设该表中包含字段“hotel_id”,“hotel_name”和其他一些字段。

现在,我们制作sql查询字符串的方法是解析看起来像这样的url请求:

index.php?task=view&table=hotels&hotel_id=1&param1=something&param2=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...

我遇到的问题是在请求网址中公开了表名和字段名。我知道这会产生安全风险,暴露出只应该向服务器端看到的项目。我正在考虑的当前解决方案是为客户端的每个表和字段提供别名 - 但这将是硬编码,这违反了他的政策。此外,如果我这样做,并且有一千个表别名,那就不实用了。

没有这样做的正确方法是什么:

  1. 硬编码的东西
  2. 使代码保持动态和适应性
  3. 修改

    关于任意查询(我忘了包含这个),当前在后端停止它们的是一个函数,它从硬编码对象(更像是这里显示的配置文件)中引用,并解析通过挑选参数或匹配它们来获取网址。

    配置如下:

    // '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,只留下配置文件是以后唯一可编辑的文件(这就是我对动态代码的意思,如果需要更多的表,我只添加表和任务)但我担心它可能会带来安全风险,我可能还不知道。

    任何替代方案的想法?

3 个答案:

答案 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()

虽然,如果在使用这些名称时相应地转义输入,我认为在公开其名称时没有任何问题。