【问题标题】:Find and Replace credit card numbers查找和替换信用卡号
【发布时间】:2012-06-27 19:48:54
【问题描述】:

我们有一个包含大量数据的大型数据库。我最近发现我们的销售和运输部门一直在使用应用程序的一部分来公开存储客户的信用卡号码。我们已经阻止了它,但现在有数千行带有数字。

我们正试图弄清楚如何扫描某些列以查找连续的 16 位数字(或破折号分隔)并将它们替换为 X。

这不是一个简单的 UPDATE 语句,因为卡号存储在大量文本中。到目前为止,我一直无法弄清楚 SQL Server 是否能够使用正则表达式(似乎没有)。

所有其他方法都失败了,我将通过 PHP 来做这件事,因为这是我最擅长的……但这会很痛苦。

【问题讨论】:

  • RegEx 在 SQL Server 中当然是可能的,只是不是本机的 - 你需要使用 CLR。网上有很多这样的例子:-codeproject.com/Articles/42764/…-justgeeks.blogspot.com/2008/08/…-可能是这里最权威的资源:-sqlmag.com/article/tsql3/clr-or-not-clr-is-that-the-question- 在 SQL Server 2008 R2+ 中,您可以通过 Master Data Services 访问一些 RegEx 功能,而无需编写自己的 CLR:-thefirstsql.com/2011/02/07/r
  • 这是一种应用程序代码往往更易于设计处理的事情。你是对的,reg ex 似乎是要走的路。您可以在 C# 中执行此操作并将其放入 CLR 存储过程中,以便可以轻松地从 SSMS 运行它。遗憾的是,由于这是在文本字段中,您可能需要确定哪些记录可能是错误的,然后让某人手动检查它们。毕竟,零件号也可能以正确的位数结束。我建议那些数据输入错误的人来做人工检查。
  • 您还可以搜索短语 credit card、card number、CCN 作为可能包含卡号的记录的线索。
  • 我同意 HLGEM。此外,考虑在前端添加验证以防止将来发生这种情况。除了告诉用户不要这样做,您还可以尝试检测是否输入了卡号,然后要求主管进行徽章扫描或其他操作。这样,它以后再次成为问题的可能性就较小。
  • 是的,您也应该清楚对用户的法律影响。如果您的系统不符合 PCI 标准,您可能会完全失去取卡的能力。

标签: sql sql-server credit-card replace


【解决方案1】:

听起来您需要将 PATINDEX 与 WHERE LIKE 子句一起使用。

类似的东西。用类似的东西创建一个存储过程,然后用你确定的一堆不同的参数(使 @pattern 和 @patternlength 成为参数)调用它,直到你替换了所有的实例。

declare @pattern varchar(100), @patternlength int
set @pattern = '[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'
set @patternlength = 19

update  tableName
set fieldName = 
    LEFT(fieldName, patindex('%'+ @pattern + '%', fieldName)-1) 
    + 'XXXX-XXXX-XXXX-XXXX' 
    + SUBSTRING(fieldName, PATINDEX('%'+ @pattern + '%', fieldName)+@patternlength, LEN(fieldName))
from tableName
where fieldName like '%'+ @pattern + '%'

诀窍就是找到合适的模式,并设置合适的@patternlength 值(不是@pattern 的长度,因为那样不行!)

【讨论】:

    【解决方案2】:

    您可以使用 patindex。它不会很漂亮,可能有更简洁的方式来编写它。但是你可以使用集合,即 [0-9]

    patindex:http://msdn.microsoft.com/en-us/library/ms188395.aspx

    类似问题:SQL Server Regular expressions in T-SQL

    【讨论】:

      【解决方案3】:

      我认为您最好以编程方式执行此操作,特别是因为您提到数据可以采用几种不同的格式。请记住,并非所有信用卡号都是 16 位数字(Amex 是 15,Visa 是 13 或 16,等等)。

      如果可能,最好在清理作业级别提供检查各种正则表达式和验证代码的能力。

      【讨论】:

      • 同意 - 我们以编程方式执行此操作。我在下面为任何想使用 PHP 的人添加了一个示例。
      【解决方案4】:

      即兴肖恩的回答。

      下面将在@text 中找到所有出现的@maskPattern 并将它们替换为'x'。 例如,如果@maskPattern = XXXX-XXXX-XXXX-XXXX,它将在@text 中找到此模式并将所有出现的地方替换为 XXXX-XXXX-XXXX-XXXX。如果它没有找到任何匹配项,它将保持文本不变。

      这个存储过程也可以被操作为只屏蔽 maskPattern 开头的 3/4。干杯!

        ALTER PROCEDURE [dbo].[SP_MaskCharacters] @text nvarchar(max),
        @maskPattern nvarchar(500)
        AS
         BEGIN
        DECLARE @numPattern nvarchar(max) = REPLACE(@maskPattern, 'x', '[0-9]')
        DECLARE @patternLength int = LEN(@maskPattern)
        WHILE (@text IS NOT NULL)
        BEGIN
        IF PATINDEX('%' + @numPattern + '%', @text) = 0  BREAK;
        SET @text =
          LEFT(@text, PATINDEX('%' + @numPattern + '%', @text)-1) --Get beginning chars of the input text until first occurance of pattern is found
          + @maskPattern --Append aasking pattern
          + SUBSTRING(@text, PATINDEX('%' + @numPattern + '%', @text) + @patternLength, LEN(@text)) -- Get & append rest of the text found after masking attern
          END
          SELECT @text
      END
      

      【讨论】:

        【解决方案5】:

        对于发现此问题但确实想使用 PHP 的任何人,这是我使用的一个函数,它采用信用卡号(所有数字,带有破折号或带有空格)并将除第一个和最后 4 位数字之外的所有数字替换为 'X '。

        要同时接受带有破折号的信用卡号,请改用此正则表达式模式:

        $cc_regex_pattern = '/(\d{4})(-)?(\d{4})(-)?(\d{4})(-)?(\d{4})/'
        

        并删除删除破折号的cc号码的预处理:

        $compressed_cc_number = preg_replace('/(\ |-)/', '', $credit_card_number);
        

        所以替换字符串变成了(因为我们已经改变了模式的索引——注意 $7):

        $cc_regex_replacement = '$1' . $cc_middle_pattern . '$7';
        

        或者,如果您愿意,只需替换整个 cc 号码,就像在原始问题中一样:

        $cc_regex_replacement = 'XXXX$2XXXX$4XXXX$6XXXX';
        

        这是信用卡号的原始函数,无论是否包含空格或破折号,它会混淆并删除任何破折号:

        /**
         * @param integer|string $credit_card_number
         * @return mixed
         */
        static function obfuscate_credit_card($credit_card_number)
        {
        
            $compressed_cc_number = preg_replace('/(\ |-)/', '', $credit_card_number);
        
            $cc_length = strlen($compressed_cc_number);
            $cc_middle_length = $cc_length >= 9 ? $cc_length - 8 : 0;
        
            //create middle pattern
            $cc_middle_pattern = '';
            for ($i = 0; $i < $cc_middle_length; $i++) {
                $cc_middle_pattern .= 'X';
            }
        
            //replace cc middle digits with middle pattern
            $cc_regex_pattern = '/(\d{4})(\d+)(\d{4})/';
            $cc_regex_replacement = '$1' . $cc_middle_pattern . '$3';
            $obfuscated_cc = preg_replace($cc_regex_pattern, $cc_regex_replacement, $compressed_cc_number);
        
            return $obfuscated_cc;
        }
        

        【讨论】:

          【解决方案6】:

          我最近遇到了这种情况。使用 Patindex 和 Stuff 应该会有所帮助,但是对于具有不同位数的 CC 号码,您需要分别重复。

          -- For 16 digits CC numbers
          UPDATE table
          SET    columnname = Stuff (columnname, Patindex(
          '%[3-6][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%'
          , columnname), 16, '################')
          WHERE  Patindex(
          '%[3-6][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%'
          , columnname) > 0 
          
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-05-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-09
            • 2019-09-02
            • 2014-09-01
            相关资源
            最近更新 更多