iT邦幫忙

2024 iThome 鐵人賽

DAY 6
1
Security

資安這條路:系統化學習網站安全與網站滲透測試系列 第 6

資安這條路:Day6 資料庫安全與使用者管理系統實作、API 安全

  • 分享至 

  • xImage
  •  

上一篇提到基於 Base64 的身份驗證,以及寫死帳號密碼於程式碼是非常不安全的事情。

image

在這個地方提到資料庫相關的概念,針對資料庫,我們將設計幾個問題讓大家更認識資料庫是什麼。

思考問題

一、 資料儲存

  • 問題: 日常生活中,我們經常需要儲存各種資訊,例如通訊錄、待辦事項、購物清單等。我們通常會如何記錄這些資訊?
  • 延伸問題: 試著比較不同記錄方式的優缺點,例如使用筆記本、手機應用程式、電腦檔案等。

二、資料庫概念

  • 問題: 當資料量變得龐大且複雜時,例如公司的人事資料、電商平台的商品資訊,單純使用筆記本或檔案記錄就會變得很困難。這時就需要用到「資料庫」來儲存和管理這些資訊。請問你們認為資料庫的出現解決了什麼問題?
  • 延伸問題: 試著想像如果沒有資料庫,我們會面臨哪些困難?

三、 關聯式資料庫的特點

  • 問題: 關聯式資料庫就像一個表格,資料以行列的方式儲存,不同表格之間可以建立關聯。請問這種儲存方式有什麼優點?
  • 延伸問題: 請舉例說明關聯式資料庫的應用場景,例如學校的學生選課系統、銀行的帳號管理系統等。

四、 非關聯式資料庫

  • 問題: 相較於關聯式資料庫的表格結構,非關聯式資料庫更加靈活,可以用來儲存各種不同格式的資料,例如文件、圖片、影片等。請問這種儲存方式有什麼優點?
  • 延伸問題: 請舉例說明非關聯式資料庫的應用場景,例如社群網站的使用者資訊、電子商務平台的商品評論等。

五、 比較關聯式和非關聯式資料庫

  • 問題: 面對不同的資料儲存需求,我們應該如何選擇合適的資料庫?
  • 延伸問題: 請比較關聯式和非關聯式資料庫的優缺點,並討論它們分別適用於哪些應用場景。

嘗試回答

一、 資料儲存

  • 問題: 日常生活中,我們經常需要儲存各種資訊,例如通訊錄、待辦事項、購物清單等。請問你們通常會如何記錄這些資訊?
    • 常見的記錄方式包括:
      • 筆記本:手寫記錄,直觀但容易遺失或難以搜尋。
      • 手機應用程式:例如待辦事項或備忘錄,容易整理,便於隨時查閱。
      • 電腦檔案:如使用Excel或Word,適合處理稍複雜的清單,但在多設備間同步不便。
  • 延伸問題: 試著比較不同記錄方式的優缺點,例如使用筆記本、手機應用程式、電腦檔案等。
    • 筆記本的優點是直觀易用,缺點是資料量增大後查找和整理不便。
    • 手機應用程式的優點是方便攜帶、可自動備份,缺點可能是功能受限。
    • 電腦檔案的優點是可以用公式和排序功能,適合處理結構化的資料,但在跨平台使用上可能較不方便。

二、 資料庫概念

  • 問題: 當資料量變得龐大且複雜時,例如公司的人事資料、電商平台的商品資訊,單純使用筆記本或檔案記錄就會變得很困難。這時就需要用到「資料庫」來儲存和管理這些資訊。請問你們認為資料庫的出現解決了什麼問題?

    • 資料庫解決了大規模資料的儲存、查詢、分類與管理問題。它允許多使用者同時操作,保證資料的一致性與完整性。
  • 延伸問題: 試著想像如果沒有資料庫,我們會面臨哪些困難?

    • 沒有資料庫的情況下,資料的存取效率會變差,資料的一致性難以維護,容易出現重複或錯誤資訊,尤其是多使用者環境下的資料同步會變得困難。

三、 關聯式資料庫的特點

  • 問題: 關聯式資料庫就像一個表格,資料以行和列的方式儲存,不同表格之間可以建立關聯。請問這種儲存方式有什麼優點?
    • 優點包括:
      • 結構化儲存,便於查詢和分析。
      • 支援複雜的查詢語句,能夠關聯多張表進行資料整合。
      • 資料完整性較高,通過外鍵和約束確保資料關聯的準確性。
  • 延伸問題: 請舉例說明關聯式資料庫的應用場景,例如學校的學生選課系統、銀行的帳戶管理系統等。
    • 學校的學生選課系統:使用關聯式資料庫管理學生、課程與老師的資訊,方便學生查詢課程、選課和老師記錄學生成績。
    • 銀行帳號管理系統:用來追蹤客戶帳號資訊、交易記錄等,確保資料的準確性和查詢效率。

四、 非關聯式資料庫的特點

  • 問題: 相較於關聯式資料庫的表格結構,非關聯式資料庫更加靈活,可以用來儲存各種不同格式的資料,例如文件、圖片、影片等。請問這種儲存方式有什麼優點?
    • 優點包括:
      • 資料格式的靈活性,可以儲存結構化或非結構化資料,如文件、圖片、JSON資料。
      • 擴展性高,適合大規模的資料處理與儲存。
      • 更適應高頻率的讀寫操作,尤其是分散式系統中的多點讀寫需求。
  • 延伸問題: 請舉例說明非關聯式資料庫的應用場景,例如社群網站的使用者資訊、電子商務平台的商品評論等。
    • 社群網站的使用者資訊:非關聯式資料庫可儲存使用者的個性化資料、好友列表、動態更新等。
    • 電子商務平台的商品評論:可以以文件格式儲存每筆評論,且不需要像關聯式資料庫那樣預先定義結構。

五、 比較關聯式和非關聯式資料庫

  • 問題: 面對不同的資料儲存需求,我們應該如何選擇合適的資料庫?
    • 需要依據資料的結構、操作的頻率、以及資料量來決定。例如:
      • 若資料具有明確的結構化需求且需要進行複雜的查詢,適合選擇關聯式資料庫。
      • 若需要處理大量的非結構化資料、快速擴展,且讀寫頻率高時,非關聯式資料庫更適合。
  • 延伸問題: 請比較關聯式和非關聯式資料庫的優缺點,並討論它們分別適用於哪些應用場景。
    • 關聯式資料庫:
      • 優點: 資料一致性強,適合結構化資料,支援複雜查詢,常用於銀行、企業系統。
      • 缺點: 當資料量巨大時,擴展性不足,難以應付高頻率的讀寫操作。
    • 非關聯式資料庫:
      • 優點: 擴展性強,支援非結構化資料,適合高頻率讀寫和大規模資料處理,如社群平台和物聯網資料。
      • 缺點: 不適合複雜的查詢,資料一致性管理困難。

資料庫相關的資安問題

「在實際的網站或應用程式中,我們應該如何安全地儲存和管理使用者資訊?」

一、 從帳號密碼儲存,探討資料加密的重要性

  • 延續先前關於 Base64 和寫死帳號密碼的安全問題,以及在關聯式資料庫中設計使用者資訊表的討論,我們進一步思考:
    • 「為什麼不能明碼儲存使用者密碼?應該如何妥善保管使用者敏感資訊?」
    • 「除了加密儲存之外,還有哪些措施可以保護資料庫的安全?」

二、 比較兩種資料庫的安全性,並討論如何提升:**

  • 思考:
    • 「關聯式資料庫和非關聯式資料庫,哪一種安全性更高?為什麼?」
    • 「針對不同的資料庫,有哪些常見的安全漏洞?應該如何防範?」
  • 目標學習:研究 SQL 注入攻擊、NoSQL 注入攻擊等常見資料庫安全問題,並思考如何透過程式碼設計、資料庫設定等方式來防範這些攻擊。

實作練習:建立資料庫、引入資料庫相關的函式

本次 github 路徑

https://github.com/fei3363/ithelp_web_security_2024/commit/5603fc4a2790e8342f5b96d8337b1b5af86ebe54

步驟一:修改 docker-compose.yml

  • 目的: 新增關聯式資料庫
  • 資安問題: 於 docker-compose.yml 寫死帳號密碼會有問題,建議使用「環境變量」。
version: '3'
services:
  app:
    build: 
      context: ./web
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - MONGODB_URI=mongodb://mongo:27017/myapp
      - POSTGRES_URI=postgresql://postgres:postgres@postgres:5432/myapp
      - NODE_ENV=development
    depends_on:
      - mongo
      - postgres
    volumes:
      - ./web:/usr/src/app
      - /usr/src/app/node_modules
    command: sh -c "npm install && npm start"

  mongo:
    image: mongo:latest
    ports:
      - "27017:27017"
    volumes:
      - mongodb_data:/data/db

  postgres:
    image: postgres:latest
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgresPassword
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  mongodb_data:
  postgres_data:

衍伸練習: 自行練習

  • 環境變數參考步驟
  • 建立 .env 檔案
MONGO_USER=your_mongo_user
MONGO_PASSWORD=your_mongo_password
POSTGRES_USER=your_postgres_user
POSTGRES_PASSWORD=your_postgres_password
  • 於 docker-compose.yml 修改 environment:
version: '3'
services:
  app:
    build: 
      context: ./web
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - MONGODB_URI=mongodb://${MONGO_USER}:${MONGO_PASSWORD}@mongo:27017/myapp
      - POSTGRES_URI=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/myapp
      - NODE_ENV=development
    depends_on:
      - mongo
      - postgres
    volumes:
      - ./web:/usr/src/app
      - /usr/src/app/node_modules
    command: sh -c "npm install && npm start"

  mongo:
    image: mongo:latest
    ports:
      - "27017:27017"
    environment:
      - MONGO_INITDB_ROOT_USERNAME=${MONGO_USER}
      - MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
    volumes:
      - mongodb_data:/data/db

  postgres:
    image: postgres:latest
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  mongodb_data:
  postgres_data:
  • 啟動的時候導入 .env 檔案
    docker-compose --env-file .env up

  • Node.js 使用這些環境變量來連接資料庫

const mongoUri = process.env.MONGODB_URI;
const postgresUri = process.env.POSTGRES_URI;

步驟二:設定資料庫連接

我們需要設定與 PostgreSQL 資料庫的連接。
web/db/postgres.js 檔案中:

const { Pool } = require('pg');

const pool = new Pool({
  connectionString: process.env.POSTGRES_URI,
});

module.exports = {
  query: (text, params) => pool.query(text, params),
};

建立一個資料庫連接方法,並使用 exports 一個 query 函數來執行 SQL 查詢。

步驟三:實現使用者控制器

web/controllers/userController.js 文件中,我們定義了處理使用者相關操作的函數:

const db = require('../db/postgres');

const userController = {
  // 建立使用者
  async createUser(req, res) {
    const { username, email, password } = req.body;
    try {
      const result = await db.query(
        'INSERT INTO users(username, email, password) VALUES($1, $2, $3) RETURNING *',
        [username, email, password]
      );
      res.status(201).json(result.rows[0]);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  },

  // 取得所有使用者
  async getAllUsers(req, res) {
    try {
      const result = await db.query('SELECT * FROM users');
      res.json(result.rows);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  },

  // 根據 ID 取得使用者
  async getUserById(req, res) {
    const { id } = req.params;
    try {
      const result = await db.query('SELECT * FROM users WHERE id = $1', [id]);
      if (result.rows.length === 0) {
        return res.status(404).json({ message: '使用者未找到' });
      }
      res.json(result.rows[0]);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  },

  // 更新使用者
  async updateUser(req, res) {
    const { id } = req.params;
    const { username, email } = req.body;
    try {
      const result = await db.query(
        'UPDATE users SET username = $1, email = $2 WHERE id = $3 RETURNING *',
        [username, email, id]
      );
      if (result.rows.length === 0) {
        return res.status(404).json({ message: '使用者未找到' });
      }
      res.json(result.rows[0]);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  },

  // 刪除使用者
  async deleteUser(req, res) {
    const { id } = req.params;
    try {
      const result = await db.query('DELETE FROM users WHERE id = $1 RETURNING *', [id]);
      if (result.rows.length === 0) {
        return res.status(404).json({ message: '使用者未找到' });
      }
      res.json({ message: '使用者已成功刪除', deletedUser: result.rows[0] });
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  }
};

module.exports = userController;

這個控制器包含了建立、讀取、更新和刪除使用者的功能。每個函數都使用 db.query 來執行相應的 SQL 操作。

步驟四:設定路由

web/routes/userRoutes.js 檔案,定義了 API 路由:

const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

router.post('/', userController.createUser);
router.get('/', userController.getAllUsers);
router.get('/:id', userController.getUserById);
router.put('/:id', userController.updateUser);
router.delete('/:id', userController.deleteUser);

module.exports = router;

這些路由將 HTTP 請求對應到相應的控制器函數。

步驟五:整合到主應用程式

最後,在 web/server.js 文件中,將使用者路由整合到主 Express 應用程式:

const express = require('express');
const path = require('path');
const userRoutes = require('./routes/userRoutes');

const app = express();

// ... 其他設定 ...

app.use('/api/users', userRoutes);

// ... 啟動伺服器 ...

這個步驟代表,就將 /api/users 路徑下的請求導向到使用者路由處理器。

小節

通過以上步驟,實現了一個基本的使用者管理系統,包括:

  1. 資料庫連接設定
  2. 使用者控制器實現 CRUD 操作
  3. RESTful API 路由設定
  4. 將路由整合到主應用程式

步驟六: 啟動之後存取瀏覽器

發現APP不存在

  • 發現資料庫不存在

步驟七:與 postgres 互動

  • 目標
    • 建立資料庫
    • 建立資料表

docker ps

進入 docker、postgres、列出DB

建立DB

  1. 進入 Docker 容器:

    root@localhost:~/nodejs_lab# docker exec -it nodejs_lab_postgres_1 bash
    

    這個指令讓你從本機(localhost)進入名為「nodejs_lab_postgres_1」的 Docker 容器的 bash 殼層。

  2. 連線到 PostgreSQL:

    root@317c8cf1536e:/# psql -U postgres
    

    在容器內,使用 postgres 使用者身份連線到 PostgreSQL。這裡顯示了容器的 ID(317c8cf1536e)。

  3. 顯示 PostgreSQL 版本資訊:

    psql (14.2 (Debian 14.2-1.pgdg110+1))
    Type "help" for help.
    

    這裡告訴我們 PostgreSQL 的版本是 14.2,運行在 Debian 系統上。

  4. 列出現有的資料庫:

    postgres=> \l
    

    這個指令列出所有現存的資料庫。從結果可以看到:

    • postgres:預設的管理資料庫
    • readme_to_recover:可能是之前建立的一個資料庫
    • template0 和 template1:這是 PostgreSQL 的預設模板資料庫
  5. 建立新資料庫:

    postgres=> CREATE DATABASE myapp;
    CREATE DATABASE
    

    建立一個名為「myapp」的新資料庫。系統回應「CREATE DATABASE」表示成功了。

  6. 連線到新資料庫:

    postgres=> \c myapp
    You are now connected to database "myapp" as user "postgres".
    

    切換到剛剛建立的「myapp」資料庫。系統確認你已經連線到新資料庫。

  7. 建立使用者資料表:

    myapp=> CREATE TABLE users (
      id SERIAL PRIMARY KEY,
      username VARCHAR(50) UNIQUE NOT NULL,
      email VARCHAR(100) UNIQUE NOT NULL,
      password VARCHAR(255) NOT NULL,
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );
    CREATE TABLE
    

    在「myapp」資料庫中建立一個名為「users」的資料表。這個表格包含:

    • id:自動遞增的主鍵
    • username:最多 50 字元的唯一使用者名稱
    • email:最多 100 字元的唯一電子郵件地址
    • password:最多 255 字元的密碼
    • created_at:自動記錄的建立時間

    系統回應「CREATE TABLE」表示表格建立成功。

步驟八:確認資料庫建立

image

出現空白代表成功

步驟九: 新增使用者

curl -X POST http://nodelab.feifei.tw/api/users -H "Content-Type: application/json" -d '{"username": "testuser", "email": "testuser@example.com", "password": "password123"}'

image

curl http://nodelab.feifei.tw/api/users

步驟十: 查看使用者

image

資安問題:

  1. 發現密碼可以明文直接看到
  2. 不需要帳號密碼就可以新增使用者
  3. 不需要帳號密碼就可以查看使用者資訊

改進建議

  1. 密碼雜湊
    • 使用 bcrypt 等雜湊演算法來進行密碼雜湊
  2. 身份驗證
    • 實現 JWT (JSON Web Token) 認證機制
    • 為敏感行為增加 Middleware 進行身份驗證
  3. 資料保護
    • 在回傳使用者資訊時,過濾掉敏感資訊如密碼
  4. 輸入驗證
    • 使用 express-validator 等庫來驗證和淨化輸入資料
  5. HTTPS
    • 在正式環境中使用 HTTPS 來加密所有通訊
  6. 紀錄和監控
    • 實現日誌系統來記錄重要操作和潛在的安全威脅

選擇題

  1. 關於關聯式資料庫和非關聯式資料庫的比較,下列哪項陳述是正確的?
    A)關聯式資料庫更適合處理非結構化資料
    B)非關聯式資料庫通常具有更好的資料一致性
    C)關聯式資料庫支援複雜的查詢操作
    D)非關聯式資料庫不適合大規模資料儲存

    答案:C

    解析:關聯式資料庫的一個主要優勢是支援複雜的查詢操作,特別是透過 SQL 語言。非關聯式資料庫通常更適合處理非結構化資料和大規模資料儲存,而關聯式資料庫則更擅長保證資料的一致性和支援複雜查詢。

  2. 在實作使用者認證系統時,下列哪種做法是最不安全的?
    A)使用 HTTPS 協定傳輸資料
    B)在資料庫中儲存密碼的雜湊值
    C)使用 Base64 編碼儲存密碼
    D)使用加鹽(salt)的密碼雜湊

    答案:C

    解析:使用 Base64 編碼儲存密碼是非常不安全的做法,因為 Base64 是一種可逆的編碼方式,很容易被解碼。正確的做法是使用不可逆的加密方法(如加鹽的密碼雜湊)來儲存密碼,同時使用 HTTPS 協定來保護資料傳輸。

  3. 在設定 PostgreSQL 資料庫連線時,以下哪種做法最安全?
    A)在程式碼中直接寫入資料庫使用者名稱和密碼
    B)使用環境變數儲存資料庫連線資訊
    C)將連線資訊儲存在公開的設定檔中
    D)使用固定的預設密碼方便團隊成員使用

    答案:B

    解析:使用環境變數儲存敏感資訊(如資料庫連線詳情)是一種良好的安全實務。這樣可以避免將敏感資訊直接寫入程式碼或設定檔中,減少資訊洩漏的風險。同時,它也便於在不同的環境(如開發、測試、生產)中使用不同的設定。

  4. 關於 SQL 注入攻擊,下列哪項陳述是正確的?
    A)只有 MySQL 資料庫容易受到 SQL 注入攻擊
    B)使用參數化查詢可以有效防止 SQL 注入
    C)SQL 注入只能用於查詢資料,不能修改資料庫
    D)對使用者輸入進行 Base64 編碼可以完全防止 SQL 注入

    答案:B

    解析:使用參數化查詢(也稱作預處理陳述式)是防止 SQL 注入攻擊的有效方法。它將 SQL 陳述式和資料分開,使得攻擊者無法插入惡意的 SQL 程式碼。SQL 注入攻擊可以影響所有類型的 SQL 資料庫,不僅限於查詢操作,還可能導致資料被修改或刪除。簡單的編碼(如 Base64)不足以防止 SQL 注入。

  5. 在 Node.js 應用程式中使用 Docker Compose 設定多個服務時,以下哪種做法是正確的?
    A)所有服務都應該使用 root 使用者執行以確保足夠的權限
    B)資料庫的使用者名稱和密碼應該直接寫在 docker-compose.yml 檔案中
    C)應該使用環境變數來管理敏感設定資訊
    D)為了方便開發,應該將所有連接埠都開放給主機

    答案:C

    解析:在 Docker Compose 設定中使用環境變數來管理敏感資訊(如資料庫憑證)是一種良好的做法。這樣可以增加安全性,同時提高設定的彈性。避免使用 root 使用者執行服務,因為這可能帶來安全風險。同樣,不應該在設定檔中直接寫入敏感資訊,也不應該不必要地開放連接埠,這些都可能增加安全風險。

實作摘要

  1. 環境設定
    • 修改 docker-compose.yml,新增 PostgreSQL 服務
    • 設定環境變數以管理敏感資訊
  2. 資料庫操作
    • 設定 PostgreSQL 資料庫連接
    • 建立資料庫和使用者資料表
  3. 後端開發
    • 實現使用者控制器(CRUD 操作)
    • 設定 API 路由
    • 整合路由到主 Express 應用程式
  4. 測試與驗證
    • 啟動應用程式並測試資料庫連接
    • 使用 curl 指令測試 API 端點
  5. 安全性改進
    • 識別現有的安全問題
    • 提出改進建議
  6. 撰寫心得與感想

作業目標

找出並測試現有 API 中可能存在的安全漏洞,並提出改進建議。

測試方向與提示

  1. 未授權存取

    • 方向:嘗試在沒有提供任何身份驗證的情況下存取需要身份驗證的端點。
    • 測試範例: curl http://nodelab.feifei.tw/api/users
  2. 參數注入

    • 方向:在請求參數中嘗試加入特殊字符或 SQL 片段。
    • 測試範例: curl -X GET "http://nodelab.feifei.tw/api/users/1 OR 1=1"
  3. 密碼明文傳輸

    • 方向:檢查密碼是否以明文形式在 API 請求或回應中傳輸。
    • 測試範例: curl -X POST http://nodelab.feifei.tw/api/users -H "Content-Type: application/json" -d '{"username": "testuser2", "email": "testuser2@example.com", "password": "password123"}'
  4. 敏感資訊洩漏

    • 方向:檢查 API 回應中是否包含不必要的敏感資訊。
    • 測試範例: curl http://nodelab.feifei.tw/api/users/1
  5. 輸入驗證

    • 方向:嘗試提供無效或異常的輸入資料。
    • 測試範例: curl -X POST http://nodelab.feifei.tw/api/users -H "Content-Type: application/json" -d '{"username": "<script>alert('XSS')</script>", "email": "invalid-email", "password": ""}'

測試步驟

  1. 對每個測試方向,使用提供的方向和測試範例進行測試。
  2. 記錄每個測試的結果,包括:
    • API 端點
    • 請求方法和參數
    • 伺服器回應
    • 觀察到的問題(如果有)
  3. 分析結果,識別潛在的安全漏洞。
  4. 對每個發現的問題,提出改進建議。

報告格式

測試項目:[測試的安全問題類型]
API 端點:[測試的 API 路徑]
請求方法:[GET/POST/PUT/DELETE 等]
請求參數:[如果適用]
測試步驟:[詳細說明如何執行測試]
預期結果:[描述安全的 API 應該如何回應]
實際結果:[描述觀察到的回應]
安全問題:[如果發現問題,描述潛在的安全風險]
改進建議:[提出如何修復或改進的建議]

上一篇
資安這條路:Day5 深入探索HTTP請求與回應:安全性與身分驗證的關鍵概念
下一篇
資安這條路:Day 7 從登入註冊功能理解 Cookie、Session
系列文
資安這條路:系統化學習網站安全與網站滲透測試30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言