styled-components 安全性

2020-07-24 16:09 更新

安全性

因为 styled-components 允许使用任意的输入作为插值使用,我们必须谨慎处理输入使其无害.使用用户输入作为样式可能导致用户浏览器中的CSS文件被攻击者替换.

以下这个例子展示了糟糕的输入导致的 API 被攻击:

// Oh no! The user has given us a bad URL!
const userInput = '/api/withdraw-funds'

const ArbitraryComponent = styled.div`
  background: url(${userInput});
  /* More styles here... */
`

请一定谨慎处理!这虽然是一个明显的例子,但是CSS注入可能隐式的发生并且产生不良影响.有些旧版本的 IE 甚至会在 url 声明中执行 JavaScript.

There is an upcoming standard to sanitize CSS from JavaScript有一个即将推出的标准,可以用于无害化 JavaScript 中的 CSS, CSS.escape. 这个标准还没有被浏览器很好的支持 .

Existing CSS

如果想将 styled-components 和现有的 CSS 共同使用,有很多实现的细节必须注意到.

styled-components 通过类生成实际的样式表,并通过className prop将这些类附加到响应的 DOM 节点. 运行时它会被注入到 document 的 head 末尾.

Styling normal React components

使用styled(MyComponent) 声明, MyComponent 却不接收传入的 className prop, 则样式并不会被呈现. 为避免这个问题,请确保组件接收 className 并传递给 DOM 节点:

class MyComponent extends React.Component {
  render() {
    // Attach the passed-in className to the DOM node
    return <div className={this.props.className} />
  }
}

对于已存在类名的组件,可以将其余传入的类合并:

class MyComponent extends React.Component {
  render() {
    // Attach the passed-in className to the DOM node
    return <div className={`some-global-class ${this.props.className}`} />
  }
}

Issues with specificity

将styled-components类与全局类混用,可能会导致出乎意料的结果.如果一个property在两个类中被定义且两个类的优先级相同,则后者会覆盖前者.

// MyComponent.js
const MyComponent = styled.div`background-color: green;`;

// my-component.css
.red-bg {
  background-color: red;
}

// For some reason this component still has a green background,
// even though you're trying to override it with the "red-bg" class!
<MyComponent className="red-bg" />

上述例子中styled-components类的样式覆盖了全局类,因为styled-components在运行时向<head>末尾注入样式.

一种解决方式是提高全局样式的优先级:

/* my-component.css */
.red-bg.red-bg {
  background-color: red;
}

避免与第三方样式和脚本的冲突

如果在一个不能完全控制的页面上部署styled-components,可能需要采取措施确保 component styles 不与 host page 上其他样式冲突.

常见的问题是优先级相同,例如 host page 上持有如下样式:

body.my-body button {
  padding: 24px;
}

因为其包含一个类名和两个标签名,它的优先级要高于 styled component 生成的一个类名的选择器:

styled.button`
  padding: 16px;
`

没有让 styled component 完全不受 host page 样式影响的办法.但是可以通过babel-plugin-styled-components-css-namespace来提高样式的优先级, 通过它可以为 styled components 的类指定一个命名空间. 一个好的命名空间,譬如#my-widget,可以实现styled-components 在 一个 id="my-widget"的容器中渲染, 因为 id 选择器的优先级总是高于类选择器.

一个罕见的问题是同一页面上两个styled-components实例的冲突.通过在 code bundle 中定义 process.env.SC_ATTR 可以避免这个问题. 它将覆盖 <style> 标签的data-styled属性, (v3 及以下版本使用 data-styled-components), allowing each styled-components instance to recognize its own tags.


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号