如何从 Sentry 错误报告中过滤敏感的 Django POST 参数?

Posted

技术标签:

【中文标题】如何从 Sentry 错误报告中过滤敏感的 Django POST 参数?【英文标题】:How do I filter sensitive Django POST parameters out of Sentry error reports? 【发布时间】:2014-07-11 18:42:45 【问题描述】:

引用Django docs:

@sensitive_post_parameters('pass_word', 'credit_card_number')
def record_user_profile(request):
    UserProfile.create(user=request.user,
                       password=request.POST['pass_word'],
                       credit_card=request.POST['credit_card_number'],
                       name=request.POST['name'])

在上面的示例中,POST 参数的 pass_word 和 credit_card_number 的值将被隐藏并替换为错误报告中请求表示中的星号 (******),而name参数的值会被公开。

要在错误报告中系统地隐藏请求的所有 POST 参数,请不要向sensitive_post_parameters 装饰器提供任何参数:

@sensitive_post_parameters()
def my_view(request):
    ...

作为测试,我将以下代码添加到我的 Django 1.6 应用程序中:

views.py:

@sensitive_post_parameters('sensitive')
def sensitive(request):
    if request.method == 'POST':
        raise IntegrityError(unicode(timezone.now()))
    return render(request, 'sensitive-test.html',
          'form': forms.SensitiveParamForm())

forms.py:

class SensitiveParamForm(forms.Form):
    not_sensitive = forms.CharField(max_length=255)
    sensitive = forms.CharField(max_length=255)

当我通过POST 提交此表单时,我可以在Sentry 报告中看到两个字段(包括sensitive)的值都清楚地显示为一天。

我在这里做错了什么?我正在使用 Django 1.6 和 Raven 3.5.2。

提前感谢您的帮助!

【问题讨论】:

DEBUG 设置为False 时? 是的,应该设置为False。我的设置文件中的确切行如下: DEBUG = (os.environ.get('DJANGO_DEBUG_MODE', 'off') == 'on') 目前,在 Heroku 环境中,DJANGO_DEBUG_MODE = off 【参考方案1】:

原来这源于 Django 本身的一个错误!

如果您没有更改您的settings 文件中的DEFAULT_EXCEPTION_REPORTER_FILTER,您将获得SafeExceptionReporterFilter 的默认过滤器。

如果您使用了sensitive_post_parameters 装饰器,这将导致您调用SafeExceptionReporterFilterget_post_parameters 方法:

 def get_post_parameters(self, request):
        """
        Replaces the values of POST parameters marked as sensitive with
        stars (*********).
        """
        if request is None:
            return 
        else:
            sensitive_post_parameters = getattr(request, 'sensitive_post_parameters', [])
            if self.is_active(request) and sensitive_post_parameters:
                cleansed = request.POST.copy()
                if sensitive_post_parameters == '__ALL__':
                    # Cleanse all parameters.
                    for k, v in cleansed.items():
                        cleansed[k] = CLEANSED_SUBSTITUTE
                    return cleansed
                else:
                    # Cleanse only the specified parameters.
                    for param in sensitive_post_parameters:
                        if param in cleansed:
                            cleansed[param] = CLEANSED_SUBSTITUTE
                    return cleansed
            else:
                return request.POST

上面的问题是,虽然它正确返回一个QuerySet,敏感的POST参数设置为CLEANSED_SUBSTITUTE'********************')...它不会以任何方式改变request.body

这是在使用 Raven/Sentry for Django 时出现的问题,因为事实证明,Raven 的 DjangoClientget_data_from_request 方法首先尝试从 request.body 获取请求的 POST 参数:

def get_data_from_request(self, request):

  [snip]

    if request.method != 'GET':
        try:
            data = request.body
        except Exception:
            try:
                data = request.raw_post_data
            except Exception:
                # assume we had a partial read.
                try:
                    data = request.POST or '<unavailable>'
                except Exception:
                    data = '<unavailable>'
    else:
        data = None

 [snip]

事实证明,最快的修复方法只是将DjangoClient 子类化并手动将其输出替换为SafeExceptionReporterFilter 生成的已清理QuerySet

from django.views.debug import SafeExceptionReporterFilter
from raven.contrib.django.client import DjangoClient


class SafeDjangoClient(DjangoClient):

  def get_data_from_request(self, request):
    request.POST = SafeExceptionReporterFilter().get_post_parameters(request)
    result = super(SafeDjangoClient, self).get_data_from_request(request)
    result['sentry.interfaces.Http']['data'] = request.POST
    return result

【讨论】:

以上是关于如何从 Sentry 错误报告中过滤敏感的 Django POST 参数?的主要内容,如果未能解决你的问题,请参考以下文章

Django 发生错误时如何将用户信息添加到 Sentry 的报告中?

使用 Sentry 时如何避免来自第三方扩展的不必要的崩溃报告?

比较 Sentry 与 Google 错误报告

如何在 Sentry 上设置源地图

如何向 Sentry 报告当前登录的用户?

django商城项目之用sentry管理日志