Подтвердить что ты не робот

Вход в карточную кредитную карточку от магнитной полосы

Кто-нибудь знает, как разбирать ввод строки кредитной карты с помощью Magnetic Card Swiper?

Я попробовал парсер JavaScript, но так и не получил его на работу. Вот как выглядит вход.

%BNNNNNNNNNNNNNNNN^DOE/JOHN
^1210201901000101000100061000000?;NNNNNNNNNNNNNNNN=12102019010106111001?

N - номер кредитной карты.

4b9b3361

Ответ 1

См. Запись карты магнитной полосы @Википедия:


Отследить один, формат B:

  • Начать дозор - один символ (обычно "%" )
  • Формат кода = "B" - один символ (только альфа)
  • Основной номер учетной записи (PAN) - до 19 символов. Обычно, но не всегда, соответствует номеру кредитной карты напечатанный на лицевой стороне карты.
  • Полевой разделитель - один символ (обычно '^')
  • Имя - от двух до 26 символов
  • Полевой разделитель - один символ (обычно '^')
  • Дата истечения срока действия - четыре символа в форме YYMM.
  • Сервисный код - три символа
  • Дискреционные данные - могут включать индикатор ключа подтверждения PIN (PVKI, 1 символ), значение подтверждения PIN (PVV, 4 символа), проверка карты Величина или код подтверждения карты (CVV или CVK, 3 символа)
  • Конечный дозор - один символ (обычно '?')
  • Проверка продольной избыточности (LRC) - один символ (большинство устройств чтения не возвращайте это значение, когда карта выталкивается на уровень представления, и использовать его только для проверки ввода внутренне читателю.)

Я надеюсь, что данные являются поддельными, иначе Любой может получить:

  • Имя
  • Дата истечения срока действия
  • CVV

И я не уверен, но я думаю, что номер кредитной карты (или # возможностей) можно вычислить с использованием LRC.

Ответ 2

Я сделал вам лучше: я сделал видео, показывающее, как это сделать с помощью ASP.Net/С#:

http://www.markhagan.me/Samples/CreditCardSwipeMagneticStripProcessing

Вот раздел кода, который вам, вероятно, волнует:

    protected void CardReader_OTC(object sender, EventArgs e)
    {
        bool CaretPresent = false;
        bool EqualPresent = false;

        CaretPresent = CardReader.Text.Contains("^");
        EqualPresent = CardReader.Text.Contains("=");

        if (CaretPresent)
        {
            string[] CardData = CardReader.Text.Split('^');
            //B1234123412341234^CardUser/John^030510100000019301000000877000000?

            PersonName.Text = FormatName(CardData[1]);
            CardNumber.Text = FormatCardNumber(CardData[0]);
            CardExpiration.Text = CardData[2].Substring(2, 2) + "/" + CardData[2].Substring(0, 2);
        }
        else if (EqualPresent)
        {
            string[] CardData = CardReader.Text.Split('=');
            //1234123412341234=0305101193010877?

            CardNumber.Text = FormatCardNumber(CardData[0]);
            CardExpiration.Text = CardData[1].Substring(2, 2) + "/" + CardData[1].Substring(0, 2);
        }
    }

Полный код находится на этом веб-сайте, который я связал выше.

Ответ 3

Из того, что я помню:

Это двухканальная магнитная полоса данных - первая дорожка начинается с % и заканчивается на ?, вторая дорожка начинается с ; и заканчивается на ?. Это маркеры Start/End.

Первый трек является буквенно-цифровым, второй трек является числовым, и есть третий трек, который также является числовым (если моя память работает правильно).

Данные между маркерами начала и конца могут быть переменными в зависимости от плотности записи магнитной полосы. Чем выше плотность, тем больше она может быть записана на одну дорожку.

Использование регулярного выражения для получения данных не может быть надежным методом для выбора необходимой информации.

И не все кредитные карты имеют ровно два трека, некоторые используют три трека.

Ответ 4

Как правило, для транзакции транзакции без транзакции (т.е. транзакций MOTO) вам потребуется cС#, истечение срока действия и, возможно, CVV (aka CVC2 и т.д.). Вы можете получить первые 2 из прокрутки карты, как это в данных дорожки. CVV печатается на карточке.

Название на карте не имеет большого значения. Если ваш покупатель и владелец карты не используют проверку адреса, но вы можете найти, что между ^^, у него может быть пробел пробела, который вы можете удалить.

Требуемая часть - track2 NNNNNNNNNNNNNNNNN = 1210, где NNNNN = номер карты PAN и 1210 = дата истечения срока действия.

Даже если трек1 пуст (что иногда бывает так, как оно не используется при обработке), вы все равно получите;?, чтобы вы могли использовать индекс второго; как начало строки и = как конец строки cС#. С 4 символами после = в качестве истечения срока действия.

Я бы посоветовал держателю карты подписать что-то в записи о транзакции, иначе они могли бы оспорить карточку и сделать перезарядку.

И не все кредитные карты имеют ровно два трека, некоторые используют три трека.

Для обработки используется только track2 и имеет стандартизованный формат.

Дебетовые карты обычно не могут быть обработаны (если у них нет визовой дебетовой карты или чего-то еще).

P.S. вы не должны хранить данные cc в обычном тексте, поэтому старайтесь хранить все в памяти или сильное шифрование.

Ответ 6

вот мой код:

1st слушатель, чтобы получить данные.... эти данные нуждаются в проверке, на которую я ищу помощь. Хороший салфетка работает отлично, но плохой салфетка вызовет ошибку в синтаксическом анализаторе.

$('#cc-dialog-form').keypress(function(e) 
{

    var charCode = e.which;
    //ie? evt = e || window.event;
    track_start = '%';
    finished = false;
    timeout = 100;
    track_start_code = track_start.charCodeAt(0);
    //console.log('Track_start_code: ' + track_start_code);

    //console.log('keycode ' + e.keycode);


    //console.log('charcode ' + charCode);
    //console.log('track_start_code ' + track_start_code);
    if (charCode == track_start_code)
    {
        collect_track_data = true;
            $('#offline_cc_entry').hide();
            $('#cc_online').hide();
            $('#Manual_CC_DATA').hide();
            $('#cc_loading_image').show();      

    }
    if (collect_track_data)
    {   
        if (charCode == $.ui.keyCode.ENTER) 
        {
            //all done
            //console.log( card_data);
            collect_track_data = false;
            $('#cc_loading_image').hide();
            $('#Manual_CC_DATA').show();
            //console.log("Track Data: " + card_data);


            process_swipe_cc_payment(card_data);
            card_data = '';

        }
        else
        {
            card_data = card_data + String.fromCharCode(charCode);
            console.log(card_data);
            if (e.preventDefault) e.preventDefault();
            e.returnValue=false;
            return false;
        }
    }
    else
    {
        //i am guessing this will be regular input?
        if (charCode == $.ui.keyCode.ENTER) 
        {
             process_keyed_or_offline_CC_payment();
        }
    }
    //console.log("which: " + e.which);
    //console.log("keyCode: " + e.keyCode);
    //track and collect data here?

});

И вот синтаксический анализатор.... note Я поместил все это в одну функцию, чтобы я мог уничтожить все переменные, чтобы они не задерживались в браузере.

    parse_data = true;
if (parse_data)
{

var parsed_card_data = {};
parsed_card_data['card_data'] = card_data;
var tracks = card_data.split("?");

//console.log ("tracks");
//console.log (tracks);
parsed_card_data['track1'] = tracks[0];
parsed_card_data['track2'] = tracks[1];
//if there is a third track we might find it under tracks[2]

//splitting the card data OPTION 1

var track1_parsed = tracks[0].split("^");

//console.log (track1_parsed);



//track1 data....
var card_number_track1 = track1_parsed[0].substring(2);


parsed_card_data['card_number_track1'] = card_number_track1;

var details2_1 = tracks[1].split(";");
details2_1 = details2_1[1].split("=");


var exp_date_track_1 = details2_1[1];
exp_date_track_1 = exp_date_track_1.substring(0, exp_date_track_1.length - 1);
exp_date_track_1 = exp_date_track_1.substring(2, 4) + "/" + exp_date_track_1.substring(0,2);
parsed_card_data['exp_track1'] = exp_date_track_1;



//now check if track one matches track 2...

track2_parsed = tracks[1].split("=");


card_number_track_2 = track2_parsed[0].substring(1);



parsed_card_data['card_number_track_2'] = card_number_track_2;
exp_date_track_2 = track2_parsed[1].substring(0,4);
exp_date_track_2 = exp_date_track_2.substring(2, 4) + "/" + exp_date_track_2.substring(0,2);
parsed_card_data['exp_date_track_2'] = exp_date_track_2;


var primary_account_number =  card_number_track1.substring(0,1);


if(card_number_track1 == card_number_track_2 &&  exp_date_track_1 == exp_date_track_2)
{
        //now make a security feature showing the last 4 digits only....
    parsed_card_data['secure_card_number'] = "xxxx " + card_number_track1.substring(card_number_track1.length-4, card_number_track1.length);




    if(card_number_track1.length == 15)
    {
        parsed_card_data['card_type'] = "American Express"; 
    }
    else if(primary_account_number == 4)
    {
        parsed_card_data['card_type'] = "Visa";
    }
    else if(primary_account_number == 5)
    {
        parsed_card_data['card_type'] = "Master Card";
    }
    else if(primary_account_number == 6)
    {
        parsed_card_data['card_type'] = "Discover";
    }
    else
    {
        parsed_card_data['card_type'] = false;
    }

    var names_1 = track1_parsed[1].split("/");
    parsed_card_data['first_name'] = names_1[1].trim();
    parsed_card_data['last_name'] = names_1[0].trim();


    //console.log("return Data");
    //console.log(return_data);

}
else
{
    parsed_card_data = false;
}

    //zero out the variables...

    tracks = '';
    track1_parsed = '';
    card_number_track1 = '';
    details2_1 = '';
    exp_date_track_1 = '';
    track2_parsed = '';
    card_number_track_2 = '';
    exp_date_track_2 = '';
    primary_account_number = '';
}

if(parsed_card_data)
{
    //console.log(parsed_card_data);
    $('#card_type').val(parsed_card_data['card_type']);
    $('#credit_card_number').val(parsed_card_data['secure_card_number']);
    $('#expiration').val(parsed_card_data['exp']);
    $('#card_holder').val(parsed_card_data['first_name']+ " " + parsed_card_data['last_name']);

    //parsed_card_data['track1'] is basically what we want???

    $('#CC_SWIPE_INSTRUCTIONS').hide();
    $('#CC_DATA').hide();
    $('#cc_loading_image').show();



    var post_string = {};
    post_string['ajax_request'] = 'CREDIT_CARD_PAYMENT';
    post_string['amount'] = $('#cc_input').val();
    post_string['card_data'] = parsed_card_data;
    post_string['pos_sales_invoice_id'] = pos_sales_invoice_id;
    post_string['pos_payment_gateway_id'] = $('#pos_payment_gateway_id').val();
    post_string['line'] = 'online';
    post_string['swipe'] = 'swipe';

    card_data = '';
                parsed_card_data = {};
    var url = 'ajax_requests.php';
    $.ajax({
            type: 'POST',
            url: url,
            data: post_string,
            async: true,
            success:    function(response) 
            {
                $('#cc_loading_image').hide();
                console.log(response);
                $('#CC_RESPONSE').show();
                $('#CC_RESPONSE').html(response);
                //here we would update the payment table - currently we will just refresh

                post_string = '';

            }
            });
    post_string = '';
}
else
{
    //error
    alert("Read Error");
    $( "#cc-dialog-form" ).dialog( "close" );
}