duanmei1930 2018-06-20 06:39
浏览 40
已采纳

解析敏感数据会将星号放在错误的位置

A string parameter is passed to the function – below are various samples of possible input data The function receives this data as a string, not an array, json or other data formats The function should parse the string and mask sensitive data. Sensitive data should be masked (replaced) with an Asterix (*) character. Sensitive data includes the fields below, but new sensitive fields should be easily added to the function as needed:

The credit card number

The credit card expiry date

The credit card CVV value

The function returns the parsed string in the same format that it was provided, but with the sensitive data now masked.

  <?php

        $testData1 = "[orderId] => 212939129
        [orderNumber] => INV10001
        [salesTax] => 1.00
        [amount] => 21.00
        [terminal] => 5
        [currency] => 1
        [type] => purchase
        [avsStreet] => 123 Road
        [avsZip] => A1A 2B2
        [customerCode] => CST1001
        [cardId] => 18951828182
        [cardHolderName] => John Smith
        [cardNumber] => 5454545454545454
        [cardExpiry] => 1025
        [cardCVV] => 100";

    $testData2 = "Request=Credit Card.Auth Only&Version=4022&HD.Network_Status_Byte=*&HD.Application_ID=TZAHSK!&HD."
            . "Terminal_ID=12991kakajsjas&HD.Device_Tag=000123&07."
            . "POS_Entry_Capability=1&07.PIN_Entry_Capability=0&07.CAT_Indicator=0&07."
            . "Terminal_Type=4&07.Account_Entry_Mode=1&07.Partial_Auth_Indicator=0&07.Account_Card_Number="
            . "4242424242424242&07.Account_Expiry=1024&07.Transaction_Amount=142931&07."
            . "Association_Token_Indicator=0&17.CVV=200&17.Street_Address=123 Road SW&17.Postal_Zip_Code=90210&17.Invoice_Number=INV19291";


    $testData3 = '{
            "MsgTypId": 111231232300,
            "CardNumber": "4242424242424242",
            "CardExp": 1024,
            "CardCVV": 240,
            "TransProcCd": "004800",
            "TransAmt": "57608",
            "MerSysTraceAudNbr": "456211",
            "TransTs": "180603162242",
            "AcqInstCtryCd": "840",
            "FuncCd": "100",
            "MsgRsnCd": "1900",
            "MerCtgyCd": "5013",
            "AprvCdLgth": "6",
            "RtrvRefNbr": "1029301923091239",
        }';

    $testData4 = "<?xml version='1.0' encoding='UTF-8'?>
                <Request>
                        <NewOrder>
                                <IndustryType>MO</IndustryType>
                                <MessageType>AC</MessageType>
                                <BIN>000001</BIN>
                                <MerchantID>209238</MerchantID>
                                <TerminalID>001</TerminalID>
                                <CardBrand>VI</CardBrand>
                                <CardDataNumber>5454545454545454</AccountNum>
                                <Exp>1026</Exp>
                                <CVVCVCSecurity>300</Exp>
                                <CurrencyCode>124</CurrencyCode>
                                <CurrencyExponent>2</CurrencyExponent>
                                <AVSzip>A2B3C3</AVSzip>
                                <AVSaddress1>2010 Road SW</AVSaddress1>
                                <AVScity>Calgary</AVScity>
                                <AVSstate>AB</AVSstate>
                                <AVSname>JOHN R SMITH</AVSname>
                                <OrderID>23123INV09123</OrderID>
                                <Amount>127790</Amount>
                        </NewOrder>
                </Request>";

    $parseNew = array("name", "amt", "amount"); //some optional fields to parse
    //this function will take a provided string, $data, and replace all credit card information including 16-digit numbers, expiry dates and 3-digit CVV numbers.
    //$parseNew is an optional field to parse other sensitive information that matches the type of information entered into $parseNew, such as the transaction amount.
    //if the strings in $parseNew matches any field in the data given, then that data will be parsed as well
    //assign each piece of given test data to a variable for each to be passed into helcimTest

    function helcimTest($data, $parseNew) {

        $lines = explode("
", $data); //split data by new lines into an array

        if (count($lines) == 1) { //if there aren't any new lines, then periods are used
            $lines = explode(".", $data); //different splits can also be added with another if, like a ,
            //print_r($lines);
        }

        for ($currLine = 0; $currLine < count($lines); $currLine++) { //loop through the lines and check for credit card information keywords as well as if theres any matches in $parseNew

            $nonos = array("cvv", "exp", "expiry", "expire", "CVV", "Exp"); //keywords of default fields to be parsed, credit card numbers need to be searched for differently
            $nonos = array_merge($nonos, $parseNew); //take optional parse data types and add it to array of default credit card data types
            //checking credit card number first
            $cardPos = strpos($lines[$currLine], "card"); //find "card" as part of Card Number 

            if ($cardPos === false) {

                $cardPos = strpos($lines[$currLine], "Card");
            }

            if ($cardPos > 0) { //if "card" is in the line, we check if "number" is also
                $numberPos = strpos($lines[$currLine], "Number");

                if ($numberPos === false) {
                    $numberPos = strpos($lines[$currLine], "number");
                }

                if ($numberPos > 0) {

                    $matches = array();
                    preg_match_all('!\d+!', $lines[$currLine], $matches); //grabs all numbers in the line and throws them in an array
                    $numberLength = 0;

                    $digits = $matches[0]; //unpack array inside matches array

                    for ($i = 0; $i < count($digits); $i++) {

                        if (strlen($digits[$i]) == 16) {

                            $theNumber = $digits[$i];
                            $numberLength = strlen($digits[$i]);
                        }
                    }

                    if ($numberLength == 16) { //when all of these things are true then this number is definitely a credit card number

                        $lines[$currLine] = str_replace($theNumber, "****************", $lines[$currLine]);
                        //print_r($lines);         
                    }
                }
            }

            //credit card number check complete

            //now to check for everythign else
            for ($i = 0; $i < count($nonos); $i++) {

                $currNono = $nonos[$i]; //current type of data we are looking to parse

                if(strpos($lines[$currLine], $currNono) > 0){ //check to see if current parsing field exists on current line

                    preg_match_all("/\d+\.\d+|\d+|[A-Za-z]+/", $lines[$currLine], $matches);
                    $sensData = $matches[0]; //unpack array from wihtin another array

                    print_r($sensData);

                    for($f = 0; $f < count($sensData); $f++){ //if we find any fields we want to parse

                        if (strcmp($sensData[$f], $currNono) == true && $f+1 != count($sensData)){

                            $hash = str_repeat("*", strlen($sensData[$f+1]));
                            $lines[$currLine] = str_replace($sensData[$f+1], $hash, $lines[$currLine]);
                        }
                    }
                }
            }
        }

        print_r($lines);
    }

    echo "Data set 1:

"; //print results
    helcimTest($testData1, $parseNew);
    echo "Data set 2:

";
    helcimTest($testData2, $parseNew);
    echo "Data set 3:

";
    helcimTest($testData3, $parseNew);
    echo "Data set 4:

";
    helcimTest($testData4, $parseNew);

The output appears as such, some of the values are correctly parsed, and some feel totally random. The first part of the function handles the credit card number alone, which is consistently parsed correctly, it's when the function reaches its bottom half that the patterns I've laid out just don't make any sense when compared to the results:

    Data set 1:

    Array
    (
        [0] => amount
        [1] => 21.00
    )
    Array
    (
        [0] => cardExpiry
        [1] => 1025
    )
    Array
    (
        [0] => cardCVV
        [1] => 100
    )
    Array
    (
        [0] => [orderId] => 212939129
        [1] =>             [orderNumber] => INV10001
        [2] =>             [salesTax] => 1.00
        [3] =>             [amount] => 21.00
        [4] =>             [terminal] => 5
        [5] =>             [currency] => 1
        [6] =>             [type] => purchase
        [7] =>             [avsStreet] => 123 Road
        [8] =>             [avsZip] => A1A 2B2
        [9] =>             [customerCode] => CST1001
        [10] =>             [cardId] => 18951828182
        [11] =>             [cardHolderName] => John Smith
        [12] =>             [cardNumber] => ****************
        [13] =>             [cardExpiry] => ****
        [14] =>             [cardCVV] => ***
    )
    Data set 2:

    Array
    (
        [0] => Account
        [1] => Expiry
        [2] => 1024
        [3] => 07
    )
    Array
    (
        [0] => Request=Credit Card
        [1] => Auth Only&Version=4022&HD
        [2] => Network_Status_Byte=*&HD
        [3] => Application_ID=TZAHSK!&HD
        [4] => Terminal_ID=12991kakajsjas&HD
        [5] => Device_Tag=000123&07
        [6] => POS_Entry_Capability=1&07
        [7] => PIN_Entry_Capability=0&07
        [8] => CAT_Indicator=0&07
        [9] => Terminal_Type=4&07
        [10] => Account_Entry_Mode=1&07
        [11] => Partial_Auth_Indicator=0&07
        [12] => Account_Card_Number=****************&07
        [13] => Account_******=****&**
        [14] => Transaction_Amount=142931&07
        [15] => Association_Token_Indicator=0&17
        [16] => CVV=200&17
        [17] => Street_Address=123 Road SW&17
        [18] => Postal_Zip_Code=90210&17
        [19] => Invoice_Number=INV19291
    )
    Data set 3:

    Array
    (
        [0] => CardExp
        [1] => 1024
    )
    Array
    (
        [0] => CardCVV
        [1] => 240
    )
    Array
    (
        [0] => {
        [1] =>                 "MsgTypId": 111231232300,
        [2] =>                 "CardNumber": "****************",
        [3] =>                 "CardExp": ****,
        [4] =>                 "CardCVV": ***,
        [5] =>                 "TransProcCd": "004800",
        [6] =>                 "TransAmt": "57608",
        [7] =>                 "MerSysTraceAudNbr": "456211",
        [8] =>                 "TransTs": "180603162242",
        [9] =>                 "AcqInstCtryCd": "840",
        [10] =>                 "FuncCd": "100",
        [11] =>                 "MsgRsnCd": "1900",
        [12] =>                 "MerCtgyCd": "5013",
        [13] =>                 "AprvCdLgth": "6",
        [14] =>                 "RtrvRefNbr": "1029301923091239",
        [15] =>             }
    )
    Data set 4:

    Array
    (
        [0] => Exp
        [1] => 1026
        [2] => Exp
    )
    Array
    (
        [0] => CVVCVCSecurity
        [1] => 300
        [2] => Exp
    )
    Array
    (
        [0] => CurrencyExponent
        [1] => 2
        [2] => CurrencyExponent
    )
    Array
    (
        [0] => AVSname
        [1] => JOHN
        [2] => R
        [3] => SMITH
        [4] => AVSname
    )
    Array
    (
        [0] => <?xml version='1.0' encoding='UTF-8'?>
        [1] =>                     <Request>
        [2] =>                             <NewOrder>
        [3] =>                                     <IndustryType>MO</IndustryType>
        [4] =>                                     <MessageType>AC</MessageType>
        [5] =>                                     <BIN>000001</BIN>
        [6] =>                                     <MerchantID>209238</MerchantID>
        [7] =>                                     <TerminalID>001</TerminalID>
        [8] =>                                     <CardBrand>VI</CardBrand>
        [9] =>                                     <CardDataNumber>****************</AccountNum>
        [10] =>                                     <***>1026</***>
        [11] =>                                     <CVVCVCSecurity>***</***>
        [12] =>                                     <CurrencyCode>124</CurrencyCode>
        [13] =>                                     <****************>*</****************>
        [14] =>                                     <AVSzip>A2B3C3</AVSzip>
        [15] =>                                     <AVSaddress1>2010 Road SW</AVSaddress1>
        [16] =>                                     <AVScity>Calgary</AVScity>
        [17] =>                                     <AVSstate>AB</AVSstate>
        [18] =>                                     <*******>**** * *****</*******>
        [19] =>                                     <OrderID>23123INV09123</OrderID>
        [20] =>                                     <Amount>127790</Amount>
        [21] =>                             </NewOrder>
        [22] =>                     </Request>
    )
  • 写回答

1条回答 默认 最新

  • donglinli2027 2018-06-20 08:12
    关注

    One Question: Are you sure that your XML Data is correct?

     <CardDataNumber>5454545454545454</AccountNum>
    

    Shouldn't it look like this:

     <CardDataNumber>5454545454545454</CardDataNumber>
    

    or like this:

     <AccountNum>5454545454545454</AccountNum>
    

    same Problem in this Line:

     <CVVCVCSecurity>300</Exp>
    

    so if you change your code-part from:

    if (strcmp($sensData[$f], $currNono) == true && $f+1 != count($sensData)){
      $hash = str_repeat("*", strlen($sensData[$f+1]));
      $lines[$currLine] = str_replace($sensData[$f+1], $hash, $lines[$currLine]);
    }
    

    to this:

    if ($f > 0 && $f < count($sensData)-1){
      $hash = str_repeat("*", strlen($sensData[$f]));
      $lines[$currLine] = str_replace($sensData[$f], $hash, $lines[$currLine]);
    }
    

    Let me explain my solution: The if Statement checks now that if $f is not 0 (the first match in the brackets) and not count of matches - 1 (so the last match in the brackets). If so, it's the content and this is changed with the fitting length of Asterix (*) characters.

    In my Test it do the work right, please comment if you have any questions!

    HINT! CurrencyExponent is matched because it contains Exp as you see: CurrencyExponent

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿
  • ¥15 kafka 分区副本增加会导致消息丢失或者不可用吗?
  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥15 stable diffusion
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘