← 中文资源

简体中文版本

postMessage 来源校验

postMessage 跨框架通信要求发送方显式指定目标 origin、接收方校验 event.origin 白名单,否则任何嵌入页都能向你的组件注入指令。

阅读英文原文

概念定义

框架无法直接调用另一个源,集成只能通过 postMessage 交谈。协议有两个信任决策:发送者把消息瞄准给谁、接收者相信谁。两者都必须显式处理,浏览器除投递外不做任何强制。

工作机制

发送方传 targetOrigin,浏览器只在接收窗口匹配时投递,否则丢弃;接收方从 event.origin 读到真实发送源。健壮的处理器先与预期源做精确比较,再校验载荷结构与通道随机数,然后才执行。

使用场景

组件嵌入、弹窗 OAuth 回跳中继、一切跨源协调。消息模式应定义为可辨识联合并做版本化;对未知类型大声拒绝,暴露嵌入双方的版本偏差。

常见误区

白名单里带路径或通配子域的条目永远匹配不上。多个嵌入方并发时需要通道标识区分消息竞态。即便校验完备,白名单内的被攻破嵌入者仍在信任边界内——消息中的机密仍应短时效、最小化。

代码示例

const COMMON_PATTERNS = [/^123456/, /password/i, /qwerty/i, /(.)\1{2,}/];

// Password strength estimation based on character-pool entropy.
export function estimatePasswordStrength(password) {
  const value = String(password);
  const pools = [
    [/[a-z]/, 26],
    [/[A-Z]/, 26],
    [/[0-9]/, 10],
    [/[^A-Za-z0-9]/, 33],
  ];
  const poolSize = pools.reduce((total, [pattern, size]) => {
    return total + (pattern.test(value) ? size : 0);
  }, 0);
  const unique = new Set(value).size;
  const effectiveLength = Math.max(unique, Math.ceil(value.length * 0.75));
  let entropyBits = poolSize > 0 ? effectiveLength * Math.log2(poolSize) : 0;
  for (const pattern of COMMON_PATTERNS) {
    if (pattern.test(value)) entropyBits *= 0.5;
  }
  if (value.length < 8) entropyBits *= 0.6;
  const thresholds = [20, 40, 60, 80];
  let score = thresholds.filter((threshold) => entropyBits >= threshold).length;
  if (value.length === 0) score = 0;
  const labels = ["very weak", "weak", "fair", "strong", "very strong"];
  return {
    entropyBits: Math.round(entropyBits),
    score,
    label: labels[score],
    poolSize,
    length: value.length,
    uniqueCharacters: unique,
  };
}