抢注防护

上线第二天

自定义短链接功能上线第二天,我打开管理后台,愣住了。

最近注册的别名:
- nike(用户 A)
- adidas(用户 A)
- apple(用户 A)
- huawei(用户 A)
- google(用户 A)
- microsoft(用户 A)
- tesla(用户 B)
- amazon(用户 B)
- samsung(用户 B)
- ...

总计:用户 A 注册了 87 个别名,用户 B 注册了 63 个别名
3 个字符以下的别名全部被占光

我一看就知道——这是域名抢注的翻版。

这些用户注册品牌名,不是为了使用,而是想倒卖。当天下午我就收到了邮件:

你好,我注册了 “nike” 这个别名。如果 Nike 公司想要,让他们联系我报价。


商标保护

第一步:关键词库

“我需要一份商标关键词库,注册时自动检查。“

class TrademarkChecker:
    """商标关键词检查"""

    def __init__(self):
        # 知名品牌(中英文)
        self.trademarks = set()
        self._load_trademarks()

    def _load_trademarks(self):
        """加载商标库"""
        # 科技品牌
        tech = {
            'apple', 'google', 'microsoft', 'amazon', 'meta', 'facebook',
            'tesla', 'nvidia', 'intel', 'amd', 'oracle', 'ibm', 'samsung',
            'huawei', 'xiaomi', 'alibaba', 'tencent', 'baidu', 'bytedance',
        }
        # 运动品牌
        sports = {
            'nike', 'adidas', 'puma', 'jordan', 'underarmour', 'newbalance',
            'fila', 'asics', 'reebok', 'converse', 'vans', 'lululemon',
        }
        # 汽车品牌
        auto = {
            'bmw', 'mercedes', 'audi', 'toyota', 'honda', 'porsche',
            'ferrari', 'lamborghini', 'maserati', 'bentley', 'rollsroyce',
            'volkswagen', 'volvo', 'ford', 'chevrolet',
        }
        # 金融
        finance = {
            'visa', 'mastercard', 'paypal', 'stripe', 'alipay', 'wechatpay',
            'jpmorgan', 'goldman', 'morganstanley',
        }
        # 常见高频词
        premium = {
            'go', 'get', 'app', 'api', 'buy', 'shop', 'sale', 'free',
            'best', 'top', 'new', 'hot', 'pro', 'vip', 'premium',
            'admin', 'support', 'help', 'blog', 'news', 'blog',
        }

        for category in [tech, sports, auto, finance, premium]:
            self.trademarks.update(w.lower() for w in category)

        # 从数据库加载额外关键词
        extra = db.query("SELECT keyword FROM protected_keywords")
        self.trademarks.update(k['keyword'].lower() for k in extra)

        logging.info(f'商标库加载完成:{len(self.trademarks)} 个关键词')

    def check(self, alias):
        """检查是否命中商标"""
        alias_lower = alias.lower()

        if alias_lower in self.trademarks:
            return {'hit': True, 'keyword': alias_lower, 'source': 'trademark'}

        # 模糊匹配(防止 "nike1" "app1e" 这类变体)
        for trademark in self.trademarks:
            if self._is_similar(alias_lower, trademark):
                return {'hit': True, 'keyword': trademark, 'source': 'similar'}

        return {'hit': False}

    def _is_similar(self, alias, trademark):
        """简单的相似度检测"""
        # 包含商标名
        if trademark in alias:
            return True
        # 数字替换(nike1)
        import re
        clean = re.sub(r'\d', '', alias)
        if clean == trademark:
            return True
        # 字母替换(app1e → apple)
        if len(alias) == len(trademark) and sum(a != b for a, b in zip(alias, trademark)) <= 1:
            return True
        return False

频率限制

每人限量

“我不能只靠商标库。抢注者还会注册一些非品牌但高价值的短词。“

class AliasRateLimiter:
    """别名注册频率限制"""

    def check(self, user_id):
        """检查用户是否还能注册自定义别名"""
        # 已注册的自定义别名数量
        count = db.query(
            "SELECT COUNT(*) as cnt FROM urls WHERE user_id = ? AND is_custom = TRUE",
            (user_id,)
        )[0]['cnt']

        # 免费用户:最多 5 个
        user = db.query("SELECT plan FROM users WHERE id = ?", (user_id,))[0]
        limits = {
            'free': 5,
            'basic': 20,
            'pro': 100
        }
        max_count = limits.get(user['plan'], 5)

        if count >= max_count:
            return {
                'allowed': False,
                'reason': f'您的套餐最多 {max_count} 个自定义别名(已用 {count} 个)',
                'upgrade': True
            }

        # 每天最多注册 3 个
        today_count = db.query("""
            SELECT COUNT(*) as cnt FROM urls 
            WHERE user_id = ? AND is_custom = TRUE 
              AND DATE(created_at) = CURRENT_DATE
        """, (user_id,))[0]['cnt']

        if today_count >= 3:
            return {
                'allowed': False,
                'reason': f'每天最多注册 3 个自定义别名(今日已注册 {today_count} 个)'
            }

        return {'allowed': True, 'remaining': max_count - count}

争议处理

如果品牌方来要别名怎么办?

“我设计了一套争议申诉流程。“

class DisputeHandler:
    """别名争议处理"""

    def submit_dispute(self, alias, claimer_info):
        """提交争议申诉"""
        # 验证申诉者身份(需要证明商标所有权)
        dispute = {
            'alias': alias,
            'claimer': claimer_info['name'],
            'trademark_proof': claimer_info['trademark_proof'],
            'contact': claimer_info['contact'],
            'status': 'pending',
            'created_at': datetime.now()
        }

        db.execute(
            """INSERT INTO alias_disputes 
               (alias, claimer, trademark_proof, contact, status)
               VALUES (?, ?, ?, ?, 'pending')""",
            (dispute['alias'], dispute['claimer'],
             dispute['trademark_proof'], dispute['contact'])
        )

        # 通知当前别名持有者
        current_owner = db.query(
            "SELECT user_id FROM urls WHERE custom_alias = ? AND is_custom = TRUE",
            (alias,)
        )
        if current_owner:
            notify_user(current_owner[0]['user_id'],
                       f'您注册的别名 "{alias}" 收到争议申诉,请在 7 天内回应')

        return {'status': 'submitted', 'note': '我们会在 7 个工作日内处理'}

    def resolve(self, dispute_id, decision):
        """解决争议"""
        dispute = db.query(
            "SELECT * FROM alias_disputes WHERE id = ?", (dispute_id,)
        )[0]

        if decision == 'transfer':
            # 转移别名给品牌方
            db.execute(
                "UPDATE urls SET user_id = ?, custom_alias = ? WHERE custom_alias = ?",
                (dispute['claimer_id'], dispute['alias'], dispute['alias'])
            )
        elif decision == 'release':
            # 释放别名,任何人可重新注册
            db.execute(
                "UPDATE urls SET is_custom = FALSE, status = 'released' WHERE custom_alias = ?",
                (dispute['alias'],)
            )

        db.execute(
            "UPDATE alias_disputes SET status = ?, resolved_at = ? WHERE id = ?",
            (decision, datetime.now(), dispute_id)
        )

黑名单

把抢注者拉黑

class SquatBlacklist:
    """抢注者黑名单"""

    def add_to_blacklist(self, user_id, reason):
        """加入黑名单"""
        user = db.query("SELECT * FROM users WHERE id = ?", (user_id,))[0]

        # 记录到黑名单
        db.execute(
            """INSERT INTO blacklist (user_id, email, ip, reason, created_at)
               VALUES (?, ?, ?, ?, ?)""",
            (user_id, user['email'], user['last_login_ip'],
             reason, datetime.now())
        )

        # 释放该用户抢注的别名
        db.execute(
            "UPDATE urls SET status = 'released' WHERE user_id = ? AND is_custom = TRUE",
            (user_id,)
        )

        # 释放的别名可以被重新注册
        released = db.query(
            "SELECT custom_alias FROM urls WHERE user_id = ? AND is_custom = TRUE",
            (user_id,)
        )
        for alias in released:
            logging.info(f'别名 "{alias["custom_alias"]}" 已被释放')

        logging.warning(f'用户 {user_id} 已加入黑名单: {reason}')

完整流程

def register_custom_alias(user_id, alias):
    """注册自定义别名(带防护)"""
    # 1. 基本验证
    if not validate_alias(alias):
        return {'error': '别名格式不合法'}

    # 2. 商标检查
    trademark = TrademarkChecker()
    tm_result = trademark.check(alias)
    if tm_result['hit']:
        return {
            'error': f'该别名涉及品牌保护关键词',
            'detail': '如需使用,请提供商标授权证明',
            'contact': 'alias-dispute@short.url'
        }

    # 3. 频率限制
    limiter = AliasRateLimiter()
    rate_result = limiter.check(user_id)
    if not rate_result['allowed']:
        return {'error': rate_result['reason']}

    # 4. 重复检查
    exists = db.query(
        "SELECT id FROM urls WHERE custom_alias = ?", (alias,)
    )
    if exists:
        return {'error': '该别名已被注册'}

    # 5. 创建别名
    db.execute(
        "UPDATE urls SET custom_alias = ?, is_custom = TRUE WHERE user_id = ? AND short_code = ?",
        (alias, user_id, short_code)
    )

    return {'success': True, 'alias': alias}

成效

上线防护后的一周:

指标防护前防护后
品牌名注册87 次0 次
抢注者账号5 个0 个(已拉黑)
正常用户受影响2 次误判(已解封)
争议申诉1 次(已处理)

“这让我想到了域名系统的历史——同样的故事,不同的时代。人类总是想抢注好名字然后倒卖。技术可以减少这种行为,但无法完全消除。”

“防抢注搞定了。但付费别名怎么定价?”