精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

構建無密碼認證:passkey入門與Go實現

開發 前端
本文粗略探討了無密碼認證技術中的一種新興方案——passkey。隨著傳統密碼認證的安全隱患日益嚴重,passkey作為FIDO聯盟提出的解決方案,利用生物識別和硬件加密以及非對稱加密等先進技術,為用戶提供了更安全、便捷的身份驗證體驗。

傳統的密碼認證一直以來都是數字時代的主流身份驗證方式。然而,用戶常常選擇易記的弱密碼并重復使用,導致賬號易受攻擊。密碼泄露、釣魚攻擊等安全問題層出不窮,超過80%的數據泄露與密碼相關。

截圖來自FIDO聯盟官網截圖來自FIDO聯盟官網

與此同時,頻繁的密碼管理和忘記密碼情況嚴重影響用戶體驗。服務商在安全保存用戶密碼方面的責任也增加了系統建設和維護的成本。為了應對這些問題,科技行業開始積極探索無密碼認證的方法。

無密碼認證利用設備生物識別、硬件加密和其他更安全的驗證手段,提供了更安全的登錄體驗。在Thoughtworks最新一期(第31期)技術雷達文檔[3]中,一種名為passkey[4]的無密碼認證技術被列入“試驗” 象限,許多讀者可能在github[5]或其他支持passkey的站點和應用中使用過這一技術了。

圖片圖片

Passkey是FIDO聯盟(Fast IDentity Online)[6]提出的一種無密碼認證解決方案[7]。FIDO聯盟是一個開放的行業協會,其核心使命是減少世界對密碼的依賴。聯盟成員包括眾多知名的科技公司和組織,如Google、微軟、Apple、Amazon等,致力于定義一套開放、可擴展、可互操作的機制,以降低用戶和設備身份驗證時對密碼的依賴。

Passkey是FIDO聯盟的首個無密碼身份認證憑據方案,支持用戶通過與解鎖手機、平板或計算機相同的方式(如生物識別(比如屏幕指紋、面部識別等)、PIN碼或圖案)登錄應用程序和網站。目前許多主流設備、操作系統原生應用、瀏覽器和站點都支持passkey技術(如下圖),這使得passkey技術在未來的無密碼認證認證領域展現出巨大的潛力。

圖片圖片

圖來自passkeys.dev(截至20241026)

在這篇文章中,我將對passkey技術進行入門介紹,并通過Go實現一個簡單的示例供大家參考。

1. passkey的工作原理

通過上面的介紹,我們大致知道了passkey是密碼的替代品,一旦使用了passkey,我們登錄網站時就無需再輸入密碼,用于網站對你的身份進行驗證的passkey存儲在你的設備本地,你頂多只需通過本地設備的生物識別(比如指紋、人臉或圖案密碼等)進行一次解鎖即可。

從技術本質來說,paaskey就是“免密登錄服務器”方案在Web服務和終端App領域的應用。沒錯!passkey就是基于非對稱加密實現的一種無密碼認證技術。下圖展示了Bob這個用戶登錄不同Web服務時使用不同passkey的情景:

圖片圖片

如果你熟悉非對稱加密的運作原理,你就可以立即get到passkey的工作原理。

注:在《Go語言精進之路:從新手到高手的編程思想、方法和技巧[8]》的第51條“使用net/http包實現安全通信”中有對非對稱加密的全面系統講解以及示例說明。如果你不是很熟悉,可以看一下我的這本書中的內容。

以上圖中的Web Service1為例,用戶Bob在注冊時會在其自己的設備(比如電腦)上創建一對私鑰與公鑰,比如Bob的bob-ws1-private key和bob-ws1-public key,私鑰會保存在Bob的設備上,而并不需要保密的公鑰則會發送給Web Service1保存。之后,Web Service1對Bob進行身份驗證的時候,只需發送一塊數據給Bob設備上的應用(通常是瀏覽器),應用會申請使用Bob的私鑰,這個過程可能需要bob輸入設備的用戶密碼或使用生物識別(比如指紋)來授權。使用Bob的私鑰對這塊數據進行簽名后,發回Web Service1,后者通過Bob保存在服務器上的公鑰對這塊簽名后的數據進行驗簽,驗簽通過,則Bob的身份驗證就通過了!當然這只是基本原理,還有很多場景、交互和技術細節,比如支持在網吧等公共計算機上借助個人的其他設備(比如手機)進行基于passkey的的身份驗證等,這些需要進一步閱讀相關規范。更多原理細節我們也會在接下來的內容中詳細說明。

不過,在進一步了解原理之前,我們先來了解一下paaskey與FIDO、webauthn之間的關系。

FIDO2[9]是一個開放的認證標準框架,旨在取代傳統密碼認證。它包含WebAuthn[10](由W3C提供的WebAPI規范)和CTAP[11](客戶端到認證器的協議),即客戶端設備和外部認證器的通信標準。FIDO2的主要目標是增強網絡安全性,支持無需密碼的安全登錄方式。

WebAuthn是FIDO2的WebAPI組件,定義了應用如何在網頁上與瀏覽器協作,以支持基于公鑰的認證方式。它允許瀏覽器和Web應用訪問用戶設備上的身份驗證器(如指紋傳感器或USB密鑰),并進行認證交互。WebAuthn作為Web標準,得到了大多數現代瀏覽器的支持。

Passkey是對FIDO2標準的應用,以實現無密碼認證。在技術棧上,Passkey利用WebAuthn和CTAP來構建實際應用體驗,從而讓用戶在支持FIDO2的Web應用中享受無密碼登錄的便捷。這三者共同實現了現代無密碼身份認證的完整生態體系。

下面我們通過一個序列圖具體了解一下paaskey的工作原理:

圖片圖片

上圖展示了Passkey的工作流程,包括注冊和認證兩個主要流程。

在passkey(即基于WebAuthn的非密碼認證機制)中,有三個主要的實體:

  • 瀏覽器(客戶端):提供 WebAuthn API
  • 服務器(即規范中的依賴方(Relying Party)):驗證用戶身份
  • 認證器(Authenticator): 生成和存儲密鑰對(認證器可以是設備內置的,如TouchID、FaceID,或外部硬件如YubiKey)。

我們先來看看注冊流程。

用戶輸入用戶名并觸發注冊流程,瀏覽器向服務器請求注冊選項,服務器生成隨機挑戰(challenge)并創建注冊選項。

瀏覽器調用WebAuthn API(navigator.credentials.create),操作系統檢查可用的認證器,并根據認證器類型調用相應的系統API。 認證器請求用戶驗證(如需要),系統根據請求的用戶驗證級別來決定驗證方式。驗證級別包括無需驗證(none)、隱式驗證(silent,比如設備已解鎖,使用之前的驗證結果)以及必須驗證(Required)。如果是必須驗證,系統會顯示驗證提示(密碼/生物識別/PIN等)。

用戶提供身份驗證信息后,認證器會生成新的公私鑰對,并將私鑰安全存儲在認證器中,公鑰和其他憑證數據(私鑰簽名后的挑戰數據)返回給瀏覽器。瀏覽器將公鑰和其他憑證發送給服務器,服務器驗證憑證(通過公鑰驗簽)并存儲公鑰,注冊完成。

接下來,我們再來看認證流程。

當用戶輸入用戶名并觸發登錄后,瀏覽器會向服務器請求認證選項,服務器生成新的挑戰并返回認證選項。

瀏覽器調用WebAuthn API (navigator.credentials.get),認證器使用私鑰對挑戰進行簽名,并返回簽名和其他斷言數據給瀏覽器。

瀏覽器將斷言發送給服務器,服務器使用存儲的公鑰驗證簽名,認證完成。

我們看到在整個注冊和身份驗證流程中,用戶都無需記憶復雜的密碼,機密信息(比如傳統的密碼)也無需傳遞給服務器保存,而公鑰本身就是隨意公開分發的,服務端甚至都無需對其進行任何加密處理。由此可以看到:passkey既提供了更好的安全性,又提供了更好的用戶體驗,是傳統密碼認證的理想替代方案之一。

注:使用另一個設備進行身份驗證的流程,大家可以自行閱讀passkey相關規范了解。

了解了原理之后,我們再來看一個簡單的示例,直觀地看看如何實現基于passkey的身份認證。

2. passkey身份認證示例

我們使用Go實現一個最簡單的基于passkey進行注冊和身份驗證的示例。在這個示例里,我們將使用webauthn官方推薦的Go包[12]:go-webauthn/webauthn來實現服務端對passkey登錄的支持。

注:本示例的工作環境為Go 1.23.0、macOS和Edge瀏覽器。

這個示例的文件布局如下:

// intro-to-passkey/demo
$tree -F .
.
├── go.mod
├── go.sum
├── main.go
└── static/
    └── index.html

首先我們通過一個靜態文件服務器提供了前端首頁,并注冊了4個API端點用于處理Passkey注冊和認證:

// intro-to-passkey/demo/main.go
func main() {
    // 靜態文件服務
    http.Handle("/", http.FileServer(http.Dir("static")))

    // API 路由
    http.HandleFunc("/api/register/begin", handleBeginRegistration)
    http.HandleFunc("/api/register/finish", handleFinishRegistration)
    http.HandleFunc("/api/login/begin", handleBeginLogin)
    http.HandleFunc("/api/login/finish", handleFinishLogin)

    log.Println("Server running on http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

關鍵的passkey配置在init函數中:

func init() {            
    var err error        
    webAuthn, err = webauthn.New(&webauthn.Config{
        RPDisplayName: "Passkey Demo",                    // Relying Party Display Name
        RPID:          "localhost",                       // Relying Party ID
        RPOrigins:     []string{"http://localhost:8080"}, //允許的源
    })                   
    if err != nil {      
        log.Fatal(err)   
    }                    
    userDB = NewUserDB() // 初始化內存用戶數據庫
}

運行該go程序后,打開localhost:8080,我們將看到下面頁面:

圖片圖片

接下來,我們先來注冊一個用戶的passkey。在注冊輸入框中輸入"tonybai",點擊“注冊”,瀏覽器會彈出下面對話框,提醒用戶將為localhost創建密鑰:

圖片圖片

點擊“繼續”,本地os會彈出身份驗證對話框:

圖片圖片

輸入你的os登錄密碼,便可繼續注冊過程。如果注冊ok,頁面會顯示下面“注冊成功”字樣:

圖片圖片

在服務器后端,上述的注冊過程是由兩個handler共同完成的,這也是webauthn規范確定的流程,大家可以結合上面的序列圖一起看。

首先是處理/api/register/begin的handleBeginRegistration,它的大致邏輯如下:

func handleBeginRegistration(w http.ResponseWriter, r *http.Request) {
    // 1. 驗證用戶名是否已存在
    if _, exists := userDB.users[data.Username]; exists {
        http.Error(w, "User already exists", http.StatusBadRequest)
        return
    }

    // 2. 創建新用戶
    user := &User{
        ID:          []byte(data.Username),
        Name:        data.Username,
        DisplayName: data.Username,
    }
    userDB.users[data.Username] = user

    // 3. 生成注冊選項和會話數據
    options, sessionData, err := webAuthn.BeginRegistration(user)
    
    // 4. 存儲會話數據
    sessionID := storeSession(sessionData)
    http.SetCookie(w, &http.Cookie{
        Name:     "registration_session",
        Value:    sessionID,
        Path:     "/",
        MaxAge:   300,
        HttpOnly: true,
    })

    // 5. 返回注冊選項給客戶端
    json.NewEncoder(w).Encode(options)
}

注意:這段代碼中的session與傳統Web應用中用于跟蹤用戶登錄狀態的session不同。這種session機制是WebAuthn協議的一部分,用于確保認證流程的安全性:

  • 防止重放攻擊:每次認證都會生成新的挑戰
  • 確保認證操作的完整性:開始認證和完成認證必須使用相同的session數據
  • 時效性控制:認證過程必須在有限時間內完成(上面示例中的有效期為5分鐘)

所以這里的session更像是一個"挑戰-響應"認證過程中的臨時狀態存儲,而不是用來維持用戶登錄狀態的傳統session。用戶的登錄狀態管理應該是在這個認證系統之上另外實現的,比如使用JWT token或傳統的session機制。

handleFinishRegistration用于處理客戶端發到/api/register/finish的完成注冊請求,它的邏輯大致如下:

func handleFinishRegistration(w http.ResponseWriter, r *http.Request) {
    // 1. 獲取并驗證會話
    sessionData, ok := getSession(cookie.Value)
    if !ok {
        http.Error(w, "Invalid session", http.StatusBadRequest)
        return
    }

    // 2. 獲取用戶信息
    username := string(sessionData.UserID)
    user := userDB.users[username]

    // 3. 驗證并完成注冊
    credential, err := webAuthn.FinishRegistration(user, *sessionData, r)
    
    // 4. 保存憑證
    userDB.Lock()
    user.Credentials = append(user.Credentials, *credential)
    userDB.Unlock()

    // 5. 清理會話
    delete(sessionStore, cookie.Value)
}

注冊passkey后,我們就可以來基于passkey進行登錄了!服務端會使用passkey對用戶進行身份驗證。

我們在登錄輸入框中輸入"tonybai",然后點擊"Passkey登錄",本地os會彈出身份驗證對話框:

圖片圖片

輸入os登錄密碼后,便可繼續身份驗證過程,如果服務端身份驗證ok,頁面會顯示下面“登錄成功”字樣:

圖片圖片

如果在登錄輸入框中輸入一個未曾注冊過的用戶名,則服務器會驗證失敗,頁面會顯示如下錯誤:

圖片圖片

和注冊過程一樣,上述的驗證過程也是由兩個handler共同完成的,這也是webauthn規范確定的流程。

首先是處理/api/login/begin的handleBeginLogin,它的大致邏輯如下:

func handleBeginLogin(w http.ResponseWriter, r *http.Request) {
    // 1. 驗證用戶是否存在
    user, ok := userDB.users[data.Username]
    if !ok {
        http.Error(w, "User not found", http.StatusNotFound)
        return
    }

    // 2. 生成認證選項和會話數據
    options, sessionData, err := webAuthn.BeginLogin(user)
    
    // 3. 存儲會話數據
    sessionID := storeSession(sessionData)
    http.SetCookie(w, &http.Cookie{
        Name:     "login_session",
        Value:    sessionID,
        Path:     "/",
        MaxAge:   300,
        HttpOnly: true,
    })

    // 4. 返回認證選項給客戶端
    json.NewEncoder(w).Encode(options)
}

之后,是handleFinishLogin處理的來自客戶端到/api/login/finish的請求,以完成登錄流程:

func handleFinishLogin(w http.ResponseWriter, r *http.Request) {
    // 1. 獲取并驗證會話
    sessionData, ok := getSession(cookie.Value)
    if !ok {
        http.Error(w, "Invalid session", http.StatusBadRequest)
        return
    }

    // 2. 獲取用戶信息
    username := string(sessionData.UserID)
    user := userDB.users[username]

    // 3. 驗證并完成登錄
    _, err = webAuthn.FinishLogin(user, *sessionData, r)
    
    // 4. 清理會話
    delete(sessionStore, cookie.Value)
}

我們看到注冊和登錄都采用兩步驗證流程,每個流程都包含開始和完成兩個步驟,同時使用會話保持認證狀態的連續性。

整個示例的前端基本由js代碼完成:

<!DOCTYPE html>
<html>
<head>
    <title>Passkey Demo</title>
    <style>
        .container {
            margin: 20px;
            padding: 20px;
            border: 1px solid #ccc;
        }
        .form-group {
            margin: 10px 0;
        }
        #status {
            margin-top: 20px;
            padding: 10px;
        }
        .error {
            color: red;
        }
        .success {
            color: green;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>注冊</h2>
        <div class="form-group">
            <input type="text" id="registerUsername" placeholder="用戶名">
            <button notallow="register()">注冊 Passkey</button>
        </div>
    </div>

    <div class="container">
        <h2>登錄</h2>
        <div class="form-group">
            <input type="text" id="loginUsername" placeholder="用戶名">
            <button notallow="login()">Passkey 登錄</button>
        </div>
    </div>

    <div id="status"></div>

    <script>
        // 工具函數:將 ArrayBuffer 轉換為 Base64URL 字符串
        function bufferToBase64URL(buffer) {
            const bytes = new Uint8Array(buffer);
            let str = '';
            for (const byte of bytes) {
                str += String.fromCharCode(byte);
            }
            return btoa(str)
                .replace(/\+/g, '-')
                .replace(/\//g, '_')
                .replace(/=/g, '');
        }

        // 工具函數:將 Base64URL 字符串轉換為 ArrayBuffer
        function base64URLToBuffer(base64URL) {
            if (!base64URL) {
                throw new Error('Empty base64URL string');
            }
            const base64 = base64URL.replace(/-/g, '+').replace(/_/g, '/');
            const padLen = (4 - (base64.length % 4)) % 4;
            const padded = base64.padEnd(base64.length + padLen, '=');
            const binary = atob(padded);
            const buffer = new ArrayBuffer(binary.length);
            const bytes = new Uint8Array(buffer);
            for (let i = 0; i < binary.length; i++) {
                bytes[i] = binary.charCodeAt(i);
            }
            return buffer;
        }

        function showStatus(message, isError = false) {
            const status = document.getElementById('status');
            status.textContent = message;
            status.className = isError ? 'error' : 'success';
        }

        // 開始注冊
        async function startRegistration(username) {
            try {
                // 1. 從服務器獲取注冊選項
                const response = await fetch('/api/register/begin', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ username }),
                });

                if (!response.ok) {
                    throw new Error(`Server error: ${response.status}`);
                }

                const responseData = await response.json();
                
                // 確保我們使用的是 publicKey 對象
                const options = responseData.publicKey;
                if (!options) {
                    throw new Error('Invalid server response: missing publicKey');
                }

                // 2. 解碼 challenge
                options.challenge = base64URLToBuffer(options.challenge);

                // 3. 解碼 user.id
                if (options.user && options.user.id) {
                    options.user.id = base64URLToBuffer(options.user.id);
                }

                console.log('Processed options:', options); // 調試輸出

                // 4. 創建憑證
                const credential = await navigator.credentials.create({
                    publicKey: options
                });

                // 5. 準備發送到服務器的數據
                const registrationData = {
                    id: credential.id,
                    rawId: bufferToBase64URL(credential.rawId),
                    type: credential.type,
                    response: {
                        attestationObject: bufferToBase64URL(credential.response.attestationObject),
                        clientDataJSON: bufferToBase64URL(credential.response.clientDataJSON)
                    }
                };

                // 6. 發送注冊數據到服務器
                const finishResponse = await fetch('/api/register/finish', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(registrationData)
                });

                if (!finishResponse.ok) {
                    throw new Error(`Server error: ${finishResponse.status}`);
                }

                showStatus('注冊成功!');
            } catch (error) {
                console.error('Registration error:', error);
                showStatus(`注冊失敗: ${error.message}`, true);
            }
        }

        // 開始登錄
        async function startLogin(username) {
            try {
                // 1. 從服務器獲取登錄選項
                const response = await fetch('/api/login/begin', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ username }),
                });

                if (!response.ok) {
                    throw new Error(`Server error: ${response.status}`);
                }

                const responseData = await response.json();
                const options = responseData.publicKey;
                
                if (!options) {
                    throw new Error('Invalid server response: missing publicKey');
                }

                // 2. 解碼 challenge
                options.challenge = base64URLToBuffer(options.challenge);

                // 3. 解碼 allowCredentials
                if (options.allowCredentials) {
                    options.allowCredentials = options.allowCredentials.map(credential => ({
                        ...credential,
                        id: base64URLToBuffer(credential.id),
                    }));
                }

                // 4. 獲取憑證
                const credential = await navigator.credentials.get({
                    publicKey: options
                });

                // 5. 準備發送到服務器的數據
                const loginData = {
                    id: credential.id,
                    rawId: bufferToBase64URL(credential.rawId),
                    type: credential.type,
                    response: {
                        authenticatorData: bufferToBase64URL(credential.response.authenticatorData),
                        clientDataJSON: bufferToBase64URL(credential.response.clientDataJSON),
                        signature: bufferToBase64URL(credential.response.signature),
                        userHandle: credential.response.userHandle ? bufferToBase64URL(credential.response.userHandle) : null
                    }
                };

                // 6. 發送登錄數據到服務器
                const finishResponse = await fetch('/api/login/finish', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(loginData)
                });

                if (!finishResponse.ok) {
                    throw new Error(`Server error: ${finishResponse.status}`);
                }

                showStatus('登錄成功!');
            } catch (error) {
                console.error('Login error:', error);
                showStatus(`登錄失敗: ${error.message}`, true);
            }
        }

        // 注冊按鈕處理函數
        function register() {
            const username = document.getElementById('registerUsername').value;
            if (!username) {
                showStatus('請輸入用戶名', true);
                return;
            }
            startRegistration(username);
        }

        // 登錄按鈕處理函數
        function login() {
            const username = document.getElementById('loginUsername').value;
            if (!username) {
                showStatus('請輸入用戶名', true);
                return;
            }
            startLogin(username);
        }
    </script>
</body>
</html>

這段代碼沒有使用任何第三方庫或框架,對js略知一二的讀者想必也能看個七七八八。

綜上,我們看到這個示例實現提供了完整的Passkey認證功能,但需要注意這是一個演示版本。在生產環境中,還需要考慮更多,比如數據的持久化存儲、更完善的錯誤處理等。

3. 小結

本文粗略探討了無密碼認證技術中的一種新興方案——passkey。隨著傳統密碼認證的安全隱患日益嚴重,passkey作為FIDO聯盟提出的解決方案,利用生物識別和硬件加密以及非對稱加密等先進技術,為用戶提供了更安全、便捷的身份驗證體驗。

在文中,我還詳細介紹了passkey的工作原理,包括注冊和登錄流程,強調了非對稱加密在身份驗證中的重要作用。此外,通過一個基于Go語言的示例,我們展示了如何實現passkey的注冊和認證功能,幫助讀者更好地理解其實際應用。

整體來看,passkey不僅提升了安全性,還改善了用戶體驗,是未來無密碼認證的有力候選方案。隨著passkey技術的發展,期待更多應用場景的出現,為用戶帶來更安全的網絡環境。

本文涉及的源碼可以在這里[13]下載。

4. 參考資料

  • passkey.org[14] - https://passkey.org
  • passkeys.dev[15] - https://passkeys.dev
  • webauthn.guide[16] - https://webauthn.guide/
  • FIDO alliance[17] - https://fidoalliance.org/
  • webauthn.io[18] - https://webauthn.io/
  • WebAuthn 規范[19] - https://www.w3.org/TR/webauthn/
  • FIDO2 文檔[20] - https://fidoalliance.org/fido2/
責任編輯:武曉燕 來源: TonyBai
相關推薦

2022-10-26 07:26:38

2023-05-04 18:20:15

2024-07-04 15:47:28

2025-05-19 08:20:00

GoLicense后端

2019-08-12 08:44:24

密碼身份認證網絡安全

2024-08-05 01:28:26

2025-03-12 08:00:00

無密碼認證工具MFA身份驗證

2024-09-14 15:44:14

2023-10-30 08:11:20

2023-05-17 16:37:29

2023-09-21 08:10:50

2015-09-02 11:52:03

802.1xEAPPEAP

2021-02-05 18:22:51

GoC剖析

2025-07-14 06:10:00

Go編程代碼

2009-08-26 10:37:49

思科認證CCNA思科認證

2013-06-06 13:10:44

HashMap無鎖

2009-12-21 14:58:57

WCF用戶密碼認證

2012-10-25 11:27:40

BYOD無感知認證Portal認證

2025-03-03 00:05:00

GoTimer調度器

2023-05-17 00:15:11

TCCXA模式
點贊
收藏

51CTO技術棧公眾號

九色|91porny| 国产成人调教视频在线观看| 亚洲午夜免费视频| 麻豆av一区二区三区| 最近免费中文字幕大全免费版视频| 希岛爱理av免费一区二区| 91国模大尺度私拍在线视频| 在线精品亚洲一区二区| 亚洲免费一级片| 久久久久.com| 久久综合网hezyo| 欧美一区二区三区成人精品| 国产精品久久久久久久久久齐齐 | 秋霞在线午夜| 久久久久国产精品厨房| 91久久爱成人| 成人毛片一区二区三区| 欧美日本久久| 一区二区国产精品视频| 国产免费a级片| 日本h片久久| 亚洲午夜久久久久久久久久久| 日韩精品极品视频在线观看免费| 国产偷拍一区二区| 日韩精品午夜视频| 国内精品久久久久久中文字幕| 卡一卡二卡三在线观看| 亚洲1区在线观看| 欧美影片第一页| 男人操女人免费软件| 美女国产在线| 国产片一区二区三区| 国产高清不卡av| 一级特黄特色的免费大片视频| 国产欧美大片| 午夜精品国产精品大乳美女| 婷婷社区五月天| 不卡中文字幕| 亚洲欧洲视频在线| 漂亮人妻被黑人久久精品| 午夜不卡一区| 欧美日韩另类一区| 成年人黄色片视频| 国产欧洲在线| 亚洲第一激情av| 亚洲精品国产suv一区88| 婷婷五月在线视频| 国产三区在线成人av| 久久久久久久久久久久久久一区| www.麻豆av| 国产精一品亚洲二区在线视频| 国产精品网站大全| 欧美另类高清videos的特点| 久久国产精品久久w女人spa| 18性欧美xxxⅹ性满足| 国产第一页在线播放| 欧美日韩三级| 国内精品久久久久影院 日本资源| 欧美另类视频在线观看| 欧美三区视频| 欧美精品成人91久久久久久久| 欧美日韩在线视频免费播放| 综合天堂久久久久久久| 久久99热这里只有精品国产| 麻豆影视在线播放| 欧美女激情福利| 久久久久久久97| 日本三级中文字幕| 免费亚洲一区| 国产精品免费一区豆花| 一级全黄裸体免费视频| 国产一区二区女| 国产高清自拍一区| 婷婷综合激情网| 久久久午夜精品理论片中文字幕| 日本欧美色综合网站免费| 国产尤物视频在线| 最新国产成人在线观看| 亚洲成人动漫在线| 成人免费图片免费观看| 欧美性xxxxxxx| 第四色婷婷基地| 久久视频社区| 亚洲第一网站男人都懂| aaaa黄色片| 日本欧美国产| 欧美肥婆姓交大片| 国产女主播喷水视频在线观看| 奇米精品一区二区三区四区 | 欧美区一区二区| 精品国产欧美一区二区| 一卡二卡三卡四卡| 久久精品亚洲人成影院| 午夜精品一区二区三区在线视频 | 6080yy午夜一二三区久久| 九九热视频免费| 中文字幕伦av一区二区邻居| 深夜福利亚洲导航| 国产亚洲欧美久久久久| 性色一区二区三区| 亚洲自拍另类欧美丝袜| 日韩a在线观看| 中文字幕一区二区三区在线播放| 福利在线一区二区| 亚洲精品国产嫩草在线观看| 日韩天堂在线观看| 男人的天堂官网| 影音先锋国产精品| 成人h视频在线观看播放| 天天摸天天干天天操| 中文字幕一区二区三区不卡| 国产精品无码av在线播放| 欧美v亚洲v综合v国产v仙踪林| 精品国产一区二区三区忘忧草| 蜜桃av乱码一区二区三区| 欧美.日韩.国产.一区.二区| 国产999在线| 免费av网站在线播放| 综合激情成人伊人| 激情内射人妻1区2区3区 | 欧美精品videossex少妇| 在线观看网站黄不卡| 久久久久亚洲av无码专区首jn| 国产欧美日韩精品一区二区免费 | 久久黄色小视频| 美女在线视频一区| 免费国产一区二区| 波多野结衣乳巨码无在线观看| 欧美精品aⅴ在线视频| 国产aⅴ激情无码久久久无码| 国产一区日韩一区| 91久久在线视频| 91精彩视频在线播放| 好吊成人免视频| 日本一区二区免费视频| 一区二区不卡| 91九色国产在线| 91短视频版在线观看www免费| 欧美性猛交xxxxx免费看| 69亚洲乱人伦| 亚洲一级网站| 国产精品久久一区二区三区| 亚洲精品天堂| 91精品国产综合久久精品麻豆| 男人天堂资源网| 日韩专区一卡二卡| 视频一区二区三| 日韩性xxx| 国产一区二区动漫| 97人妻一区二区精品视频| 久久久五月婷婷| 国产男女无遮挡| 亚洲综合小说图片| 日本精品中文字幕| 国产在线黄色| 欧美日韩视频在线第一区 | 国产成人一区| 国产精品xxxxx| 电影在线高清| 欧美视频在线不卡| 波兰性xxxxx极品hd| 麻豆91精品91久久久的内涵| 亚洲在线色站| 亚洲精品tv| 欧美精品亚州精品| 黑人乱码一区二区三区av| 亚洲最大的成人av| 女同性恋一区二区三区| 亚洲专区一区| 欧美一区免费视频| 日韩一级特黄| 欧美多人乱p欧美4p久久| 天天操天天干天天插| 欧美午夜久久久| 亚洲毛片亚洲毛片亚洲毛片| 美女视频网站久久| 精品人妻大屁股白浆无码| 好吊妞视频这里有精品| 88国产精品欧美一区二区三区| 日韩三级电影网| 欧美日韩一区二区在线观看| 一区二区视频免费看| 成人av在线资源| 欧美精品第三页| 91成人影院| 九色综合日本| 伊人久久大香伊蕉在人线观看热v 伊人久久大香线蕉综合影院首页 伊人久久大香 | 久色婷婷小香蕉久久| 97超碰在线视| 欧美精品第一区| 91久久久久久久久久久| 999福利在线视频| 一区二区亚洲欧洲国产日韩| 国产夫妻性生活视频| 精品高清一区二区三区| 天堂av网手机版| 不卡av在线网| 一区二区xxx| 亚洲国产高清视频| 亚洲图片都市激情| 久久99偷拍| 成人乱色短篇合集| 日韩欧美精品一区二区三区| 久久精视频免费在线久久完整在线看| 黄色小视频免费观看| 在线精品视频免费观看| 精品午夜福利在线观看| 日本一区二区三区高清不卡| 国产精九九网站漫画| 日本特黄久久久高潮| 热99这里只有精品| 一区二区影院| 午夜精品视频在线观看一区二区| gogo人体一区| 91久久国产婷婷一区二区| 精品国产免费人成网站| 欧美大尺度在线观看| 成人午夜影视| 国产午夜精品理论片a级探花| 国产探花精品一区二区| 欧美丝袜自拍制服另类| 午夜毛片在线观看| 一区二区高清在线| 久久av红桃一区二区禁漫| 久久久午夜电影| 水蜜桃av无码| 丰满亚洲少妇av| 亚欧精品在线视频| 精品一区二区三区久久| 在线视频日韩一区| 性伦欧美刺激片在线观看| 精品人妻人人做人人爽| 天天做天天爱综合| 亚洲精品一区二区毛豆| 国产一区国产二区国产三区| 久久天堂国产精品| 国产美女撒尿一区二区| 99re视频在线观看| 国产一区二区三区免费在线| 成人高清视频观看www| 六九午夜精品视频| 国产精品亚洲欧美导航| 影视一区二区三区| 国产精品久久久久久搜索 | 91福利在线观看| 久久99国产综合精品免费| 婷婷丁香激情综合| 天天操天天爽天天干| 亚洲成人免费视频| 久久久久久久久久免费视频| 亚洲va天堂va国产va久| 丰满少妇乱子伦精品看片| 天天色综合天天| www.av麻豆| 日韩欧美有码在线| 久久久精品视频网站| 色综合色综合色综合色综合色综合 | 日韩电影免费网址| 中文字幕一区二区三区四区五区六区 | 欧美高清性xxxxhd| 国产99久久久国产精品成人免费 | 女人偷人在线视频| 国产一区二区三区视频免费| 一本一道波多野毛片中文在线 | 四虎成人免费影院| 国产精品三级电影| 91久久国产综合| 亚洲一区影音先锋| 欧美日韩乱国产| 在线免费观看视频一区| 中文字幕a级片| 欧美一区二区三区不卡| 蜜桃av鲁一鲁一鲁一鲁俄罗斯的| 亚洲精品v欧美精品v日韩精品| 三级在线电影| 亚洲欧洲日韩国产| 哥也色在线视频| 97色伦亚洲国产| 精品欧美一区二区三区在线观看 | 日本一区免费视频| 国产日韩欧美在线观看视频| 一区二区三区不卡在线观看| 久久露脸国语精品国产91| 色婷婷综合激情| 国产欧美第一页| 亚洲国产精品女人久久久| 精品一二三区视频| 久久av在线看| 免费看av不卡| 亚洲www永久成人夜色| 精品福利一区| 伊人久久大香线蕉成人综合网| 欧美日韩亚洲一区二区三区在线| 92看片淫黄大片一级| 狠狠色丁香婷婷综合| 欧美无人区码suv| 一区精品在线播放| 日韩av大片在线观看| 欧美人体做爰大胆视频| 三级网站免费观看| 久久精品最新地址| 午夜激情成人网| 成人在线免费观看一区| 欧美精品尤物在线观看| 成人免费在线网| 久久se这里有精品| 亚洲国产精品成人综合久久久| 国产精品国产三级国产普通话三级| 国产亚洲色婷婷久久99精品| 欧美三级日韩在线| 性xxxxbbbb| 色综合久久88色综合天天看泰| 亚洲日本天堂| 国产精品乱子乱xxxx| 久久免费av| 热久久精品国产| eeuss影院一区二区三区| 神马久久精品综合| 欧美视频一区二区在线观看| 头脑特工队2免费完整版在线观看| 久久午夜a级毛片| 韩国精品视频在线观看| 久久偷看各类wc女厕嘘嘘偷窃| 欧美日韩国产精品一区二区亚洲| 粉色视频免费看| 欧美国产日韩a欧美在线观看| 国产精品成人av久久| 日韩一级欧美一级| 色影视在线观看| 国产成人一区二区三区| 日韩有码一区| 尤物av无码色av无码| 国产69精品久久99不卡| 顶臀精品视频www| 欧美精品久久天天躁| 国产高清在线| 日本高清久久天堂| 猛男gaygay欧美视频| 人人干视频在线| 成人动漫在线一区| 国语对白一区二区| 亚洲第一网中文字幕| 黄视频网站在线观看| 久草精品电影| 亚洲免费综合| 最新中文字幕视频| 欧美日韩综合视频| 日韩av成人| 欧美一级电影免费在线观看| 网红女主播少妇精品视频| 日韩人妻精品无码一区二区三区| 99这里都是精品| 日本在线播放视频| 亚洲视频在线观看免费| free欧美| 亚洲电影网站| 韩国三级在线一区| 黄页网站免费观看| 精品美女在线播放| 爱啪啪综合导航| 久久一区二区精品| 人禽交欧美网站| 三上悠亚在线观看视频| 欧美一卡2卡三卡4卡5免费| 深夜国产在线播放| 国产精品久久久久久免费观看| 亚洲深夜影院| 免费看裸体网站| 91精品国产高清一区二区三区| 高清免费电影在线观看| 国产精品中出一区二区三区| 亚洲综合欧美| 亚洲图片第一页| 日韩精品一区二区三区视频在线观看| 好吊日av在线| 欧美专区一二三 | 欧美精品大片| 西西大胆午夜视频| 欧美日韩精品系列| 特级毛片在线| 欧美日本韩国国产| 国产在线麻豆精品观看| 福利一区二区三区四区| 在线成人一区二区| 亚洲无线观看| 久久精品免费网站| 亚洲国产一区二区在线播放| 欧美视频综合| 91在线视频成人| 先锋影音久久久| 玖玖爱这里只有精品| 日韩精品久久久久久福利| 综合久草视频| 国产日产欧美视频| 一区二区高清在线| sese一区| 精品在线观看一区二区| 激情综合网激情| 波多野结衣 久久| 色综合久综合久久综合久鬼88|