如何安全地管理一次性脚本来修复数据?

Jam*_*sen 5 ruby security debugging ruby-on-rails

偶尔,软件会出问题.当出现问题时,可能发生的最糟糕的事情之一是系统将某些数据保留在不一致或无效的状态.当然,我们试图减少这些情况,但它们确实发生了.

它们发生时,我们通常必须采取一些数据清理的形式采取纠正措施.(除了加强允许不一致的代码之外.)我在清理中看到的一些技术包括

  1. 直接编辑生产数据库
  2. 使用像Rails这样的REPL rails console来通过代码编辑生产数据
  3. 编写脚本然后运行它
  4. 编写Rails迁移然后运行它

与直接访问版本相比,脚本和迁移版本具有以下几个优点:

  1. 团队可以使用拉取请求或其他代码审查技术来确保脚本按预期运行
  2. 脚本留下来作为团队所做事情的记录
  3. 该脚本可以在非生产环境中运行,也可以在"干运行"模式下运行

不幸的是,如果签入,这些脚本也具有明显的安全劣势:它们将PII或其他敏感数据从数据库泄漏到源代码控制中.例如,

# 2013-07-05: delete all of Susan Yee's OAuth tokens because she's locked out
User.find_by_email('susan.yee@example.com').oauth_tokens.delete_all!
Run Code Online (Sandbox Code Playgroud)

我可以想到几种解决这种风险的方法:

  1. 喜欢脚本中的不透明标识符.我是这样的,但是(a)它并不总是可能的,(b)它也准确地模糊了正在发生的事情,减少了审计日志的价值.
  2. 移动防火墙内的所有源代码控制.这肯定更安全,但意味着团队无法利用许多基于云的工具(例如Code Climate,TravisCI)
  3. 将脚本与种子数据分开.以参数化方式编写脚本,即使它们只使用一次.这样可以将敏感数据保留在源代码控制之外,但这意味着所做内容的记录更难拼凑起来.

有没有人有成熟的技术?

mde*_*tis 2

首先我要说的是,我在工作期间必须执行的纠正措施从未如此频繁或复杂,需要编写专门的脚本;所以我总是停止到你所说的第1点和第2点(直接编辑数据库或使用rails console)。

无论如何,这里有几个想到的解决方案:

  1. 使脚本变得通用,这样它就可以涵盖您想要修复的情况,而无需指定“ad personam”数据。在这种情况下,您的示例(为了完整性我在此处报告):

    # Delete all of Susan Yee's OAuth tokens because she's locked out
    User.find_by_email('susan.yee@example.com').oauth_tokens.delete_all!
    
    Run Code Online (Sandbox Code Playgroud)

    变成这样的东西:

    # Delete locked out people OAuth tokens
    User.locked_out.each{ |u| u.oauth_tokens.delete_all! }
    
    Run Code Online (Sandbox Code Playgroud)

    优点是脚本有逻辑性,涵盖一般情况;(大)缺点是,您并不总是拥有可用于查找要编辑的数据的状态,并且对于这些情况(“广告人物”情况),此解决方案不适用。

  2. 通过参数/环境变量/git-ignored 文件传递​​敏感数据

    当我必须存储每个应用程序信息(例如 Rails 密钥)时,我会使用此方法:我将其放入一个文件(类似config/.secret_key这样),该文件是 git 忽略的,然后我将应用程序密钥放在那里。

    但 git-ignored 文件是用于持久数据的;由于您正在处理一次性脚本,我认为参数是一个很好的解决方案:

    # Delete all OAuth tokens of the specified user
    User.find_by_email(ARGV[0]).oauth_tokens.delete_all!
    
    Run Code Online (Sandbox Code Playgroud)

    然后运行,history -c这样即使有人设法泄露您的历史记录,您也是安全的(尽管在这种情况下您可能会遇到更大的问题:P)

    如果您还必须存储所做编辑的信息,则此解决方案不太适合;但我不认为这是你的情况,无论如何日志文件应该包含有关你所做的事情的信息。如果您有这种需求,可能最好使用一些数据库版本控制逻辑(如果您对此感兴趣,这里有一些关于此的资源)