yumetodoの旅とプログラミングとかの記録

旅や登山の記録やプログラミング関連の話とかフリーソフト紹介とか

: 一文字の定義

一文字、と一口にいってもいろいろある。というか4つある。

Q: How are characters counted when measuring the length or position of a character in a string?
http://unicode.org/faq/char_combmark.html#7

いっつもこのURL思い出せないのでメモ。

チケット購入サイトeplusのログインシステムのバグ

はじめに

知り合いに増矢馨子さんというピアニストの方がいる。

www.kaorukomasuya.com

  • Webページはどうやら更新されていない

で、今度、10/10に室内楽のコンサートがある。

web.archive.org

それのチケットがいつもと違ってチケットぴあではなくeplusだったので、会員登録をすることにしたのだ。

eplusのここがまずだめ

  • ログイン中かわからない
  • ログアウト方法がないor不明瞭
  • ログインしててもチケット購入のときはまたログインさせられる

eplus.jp

訪れればわかる、この糞of糞感。

本題

会員登録を無事に終え、チケット購入をしようとしたら、ログインを求められた、ログインしてるのに。でそれはとりあえずスルーして、ログインができない。

www.youtube.com

リアルキーボードクラッシャーやって、隣りにいた母親に怒られた。

原因

セキュリティをちょっとわかる勢C++erである私は当然KeePassでパスワードを自動生成した。しかしその自動生成したパスワードの長さが20文字だった。

eplus pass word change

パスワード登録画面には、

8文字以上16文字以下

という記述がある。

おかしい

いやちょっとまって、最初の登録の時に20文字ぶち込んでもなにもエラーにならなかったぞ、つまり入力フォームのValidationをしていない・・・?

検証したところ、登録時にいれた20文字の末尾が削られて16文字として登録されていた。

送信部分のソースコードを見てみる

幸いいかにもレガシー感漂うこのサイトのJavaScriptはminifyされていなかった。しかもHTML直書きだった。わぉ。

まずは登録フォームのほう。

$(document).ready(function() {
    // Validatorクラスのインスタンスを生成する。
    // 引数は入力チェック対象となるフォームのjQueryオブジェクト
    var validator = new Validator($('#registerMemberForm'));

    // 項目に必須属性を追加する
    var requiredFields = [];
    $('em.required').each(function() {
        if($(this).attr('epName')){
            var fields = $(this).attr('epName').split(",");
            $.each(fields,function(i,val){
                var field = $('input[name="' + val + '"]');
                if(field.length != 0){
                    requiredFields.push(field);
                }
                var field = $('select[name="' + val + '"]');
                if(field.length != 0){
                    requiredFields.push(field);
                }
            });
        }
    });

    validator.required(requiredFields);

    // ValidatorForHanyoKomokuインスタンス生成
    var validatorForHanyoKomoku = new ValidatorForHanyoKomoku("/api/v1/FTRegisterMember/hanyoKomokuCheck");

    // 確認ボタン押下
    $("#main-submit").on('click', function() {

        // 入力チェック前にアコーディオンが閉じられていた場合、入力チェック用にcss変更.非表示の場合にvalidation対象外になってしまうため
        var accordionChange = false;
        var detailsBox = $("#registerMemberForm .accordionBox .detailsBox");
        if(detailsBox.css('display') == 'none'){
            detailsBox.css('display','block');
            accordionChange = true;
        }

        // 入力チェックを実行する。
        var validError = validator.validate();
        var hanyoError = validatorForHanyoKomoku.validate();

        // cssを元に戻す
        if(accordionChange){
            detailsBox.css('display','none');

            // アコーディオン内に入力エラーがあった場合は開いて表示
            if(detailsBox.find(".errorCell").length != 0){
                accordionBoxChange(true);
            }
        }

        if(!validError || !hanyoError){
            window.scrollTo(0,dispErrorObj.offset().top);
            return false;
        }

        // 汎用項目のAJAX送信用パラメータを設定(リスト化された項目がパラメータ設定されないためここで設定.ajaxPostForFormではvalueListがString配列であることが特定できないためvalidateのjsに処理を記載)
        var param = {};
        param.soshikiHanyoKomokuSetList = validatorForHanyoKomoku.get();

        // 事前チェックでOKなら確認画面へ
        $.ajaxPostForForm(contextpath + "/api/v1/FTRegisterMember/updateCheck", $('#registerMemberForm'),param)
        .done(function(data, status, xhr, infoMessages, hasWarnings, warnMessages, hasErrors, errorMessages) {
            var res = $.parseJSON(xhr.responseText);
            if (res.isSuccess) {
                // 遷移する。
                $.doSubmit($("#registerMemberForm"), {
                    op : "startInitConfirmMemberInfo"
                });
            }
            else {
                // エラー時はダイアログ表示
                $.infoMsgBox(res.msgs[0].msg);
            }
        });
    });
    //後略
});

あれ、Validationあるじゃん。

次はパスワード変更ページ。

$(document).ready(function(){
    // 必須属性付与
    var validator = new Validator($('#updatePasswordForm'));
    validator.required([$('input[name="newPassword"]'), $('input[name="passwordConf"]')]);

    // 変更
    $('#update').click(function (e) {
        // 入力チェック
        if (!validator.validate()) {
            window.scrollTo(0,dispErrorObj.offset().top);
            return false;
        }
        $.doSubmit($("#updatePasswordForm"), {op : "startInitComplete"});
    });
});

あれ、Validationあるじゃん。ちなみに処理を追いきれなかったが、おそらく^[0-9a-zA-Z_\-@.]{8,16}$という正規表現で確認している。

しかし、会員登録ページのほうは16文字を超えても受け付けてしまう

結論

会員登録ページのValidationバグ

chromeにWebUSBが実装されたそうだが危険らしいので無効にする

先日こんなふうに大量にWebUSBやばいぞ的なツイートが流れていた。実のところ私はさっぱり理解していない。とりあえずなんかdescriptorsが云々言っているので、規格書の該当箇所を見に行く。

WebUSB API#webusb-platform-capability-descriptor

§4. WebUSB Descriptors and Requests

This specification defines descriptors and commands the UA MAY use to gather information about the device specific to implementing this API.

§4.1. WebUSB Platform Capability Descriptor

A device announces support for the WebUSB command set by including the following Platform Descriptor in its Binary Object Store:

Offset Field Size Value Description
0 bLength 1 Number Size of this descriptor. Must be set to 24.
1 bDescriptorType 1 Constant DEVICE CAPABILITY descriptor type ([USB31] Table 9-6).
2 bDevCapabilityType 1 Constant PLATFORM capability type ([USB31] Table 9-14).
3 bReserved 1 Number This field is reserved and shall be set to zero.
4 PlatformCapabilityUUID 16 UUID Must be set to {3408b638-09a9-47a0-8bfd-a0768815b665}.
20 bcdVersion 2 BCD Protocol version supported. Must be set to 0x0100.
22 bVendorCode 1 Number bRequest value used for issuing WebUSB requests.
23 iLandingPage 1 Number URL descriptor index of the device’s landing page.

bDescriptorTypeのことか?(全く無知なので間違ってたらすまん)

[USB31] Table 9-14を見てこいみたいなことを言っているので見に行く。

USB.org - DocumentsよりUniversal Serial Bus Revision 3.2 Specificationを落とす。103 MBもあるし通信速度が遅いが仕方ない。unzipしてUSB 3.2 Revision 1.0.pdfを見に行く。

§9.4 Standard Device Requests

This section describes the standard device requests defined for all devices. Table 9-4 outlines the standard device requests, while Table 9-5 and Table 9-6 give the standard request codes and descriptor types, respectively.

Devices shall respond to standard device requests, even if the device has not yet been assigned an address or has not been configured. If a standard request defines a persistent parameter that can be modified, the reset/default value for that parameter, unless otherwise specified, is zero.

Descriptor types are used to determine the type of descriptor being queried from a device or being set to a device. The existing standard descriptor types are listed in Table 9-6. All these values shall not be redefined and used in any USB class specification. In addition, this specification reserves the highest bit (Bit 7) of the descriptor type as a value that shall only be used by base USB specifications when defining new descriptor types .

Table 9-6. Descriptor Types

Descriptor Types Value
DEVICE 1
CONFIGURATION 2
STRING 3
INTERFACE 4
ENDPOINT 5
Reserved 6
Reserved 7
INTERFACE_POWER 8
OTG 9
DEBUG 10
INTERFACE_ASSOCIATION 11
BOS 15
DEVICE CAPABILITY 16
SUPERSPEED_USB_ENDPOINT_COMPANION 48
SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION 49

The INTERFACE_POWER descriptor is defined in the current revision of the USB Interface Power Management Specification.

うん、全くわからん。

とにかく

まあdescriptorsがなくても列挙可能で認可を求めるChromeのUIにユーザーが判断するために必要と思われる情報が載っていないために、とりあえず無効にしとけ、という話でいいのか?

chrome://flags/#enable-webusb

にアクセスして

chorme_web_usb_flag

Disabledに。

Chromeを再起動すれば適応されます。