Astro 5.9

作者
Emanuele Stoppa
Matt Kane

Astro 5.9 让您的网站固若金汤,它提供了对内容安全策略的实验性支持、在内容加载器中渲染 Markdown 等等!

🔒 严阵以待

要升级现有项目,请使用自动化的 @astrojs/upgrade CLI 工具。或者,通过运行包管理器的升级命令来手动升级

# Recommended:
npx @astrojs/upgrade
# Manual:
npm install astro@latest
pnpm upgrade astro --latest
yarn upgrade astro --latest

实验性内容安全策略支持

跨站脚本 (XSS) 攻击是网站面临的最常见的威胁之一。默认情况下,网页可以从任何来源加载它们想要的脚本和样式。抵御 XSS 攻击最有效的防御方法就是限制这一点。内容安全策略 (CSP) 允许您通过工具将页面锁定到受信任的资源列表,从而实现这一点。

虽然这些是强大的工具,但手动实现它们可能很棘手:如果您的框架能为您完成,会容易得多。Astro 5.9 引入了开箱即用的实验性 CSP 支持,使您的 Astro 项目更容易获得安全性。这是 Astro 迄今为止最受欢迎的功能请求,我们确实花了一些时间来实现它。我们希望这值得您的等待!

我们设计此功能旨在适用于所有 Astro 渲染模式(静态页面、动态页面和单页应用),并考虑了最大的灵活性和类型安全。没错,您没听错!您可以摆脱令人不快的 unsafe-inline 变通方法,使用所有您喜欢的 Astro 功能,适用于任何运行时的任何适配器,并为您的网站添加额外的安全层。

工作原理

用户喜欢 Astro 的原因之一是它可以在任何地方运行——静态主机、无服务器主机、Node.js、边缘运行时,以及与许多前端库(React、Vue、Svelte 等)配合使用。正因如此,Astro 的 CSP 解决方案必须与任何库在任何地方都能正常工作。

我们首先考虑了两种支持 CSP 的常见方法

  • nonce 头,它为每个请求生成一个随机值并将其注入到 HTML 中。
  • 计算传输到浏览器的所有资源的哈希值,确保只有您期望运行的脚本和样式才能执行。

虽然 nonce 头实现起来很简单,但它需要一个服务器/边缘函数,能够生成 nonce 的随机值,将 Content-Security-Policy 头添加到 Response 对象中,并重写 HTML 以便为每个 <script><style> 元素注入 nonce 值。此解决方案不适用于从静态主机(例如 GitHub Pages)提供的网站,也不适用于单页应用 (SPA),因为在应用程序生命周期中脚本和样式可能会动态注入。

生成哈希值实现起来更复杂,因为它需要知道页面上每个脚本和样式表的精确内容。然而,它比 nonce 头支持更多的用例,所以我们的选择很明确,即使前方还有另一个岔路口在等着我们。

CSP 标准允许通过名为 Content-Security-Policy 的响应头或使用名为 http-equiv='content-security-policy'<meta> 元素向浏览器提供哈希值。正如您可能猜到的,使用响应头不适用于 Astro,因为它会排除静态网站和 SPA。因此,我们决定使用 <meta> 元素向浏览器提供 CSP。

最终结果是,Astro 的 CSP 将为您生成 <meta> 元素,其中包含页面中将使用的所有脚本和样式的哈希值,甚至包括那些将动态加载的!

用法

要立即在您自己的项目中试用 Astro 的 CSP,请启用新的实验性标志

astro.config.mjs
import { defineConfig } from "astro/config"
export default defineConfig({
experimental: {
csp: true
}
})

如果您已经通过中间件或其他方式在您的网站中使用了 Content-Security-Policy 头,您仍然可以使用它,浏览器将采用头部和 <meta> 元素中更严格的策略。

但我们并未止步于此!Astro 通过配置让您进一步控制 <meta> 内容。您可以更改默认算法、插入附加指令等等

astro.config.mjs
import { defineConfig } from "astro/config"
export default defineConfig({
experimental: {
csp: {
// change the default algorithm
algorithm: "`SHA-512",
// insert additional directives
directives: [
"default-src: 'self'",
"image-src: 'https://images.cdn.example.com'"
],
// add more information to the `style-src` directive
styleDirective: {
hashes: [
"sha384-somehash" // hash generated for some external style e.g. white label, etc.
],
// **Override** default resources
resources: ["self", "https://styles.cdn.example.com"]
},
// add more information to the `style-src` directive
scriptDirective: {
hashes: [
"sha384-somehash" // hash generated for some external script e.g. analytics, jQuery, etc.
],
// **Override** default resources
resources: ["self", "https://script.cdn.example.com"],
// Toggle the keyword `strict-dynamic`
scriptDynamic: true
}
}
}
})

有关更多详细信息,请参阅实验性 CSP 文档

在内容加载器中渲染 Markdown

Astro 内容集合一直支持使用 render() 函数和 <Content /> 组件渲染 Markdown 文件,并且 Astro 5 增加了对 任何加载器渲染任何 HTML 内容的支持。但是,如果您想在内容加载器中渲染 Markdown 内容,则必须自己处理 Markdown 解析。这可能会令人困惑,因为它与 Markdown 在您网站其他部分的渲染方式不一致,并且没有使用相同的 Markdown 配置。

Astro 5.9 为加载器上下文添加了一个新的辅助函数——renderMarkdown——它允许您直接在加载器中渲染 Markdown 内容。它使用与 Astro 中用于 Markdown 文件的渲染器相同的设置和插件,包括在 Astro 项目中配置的任何 Markdown 设置。

renderMarkdown 函数在加载器上下文中可用,并返回一个包含两个属性的对象:htmlmetadata。这些与内容集合中内容条目的rendered 属性匹配,因此它们可以用于轻松地在加载器中添加对 render() 的支持。

import type { Loader } from 'astro/loaders';
import { loadFromCMS } from './cms';
export function myLoader(settings): Loader {
return {
name: 'my-loader',
async load({ renderMarkdown, store }) {
const entries = await loadFromCMS();
store.clear();
for (const entry of entries) {
// Assume each entry has a 'content' field with Markdown content
store.set(entry.id, {
id: entry.id,
data: entry,
rendered: await renderMarkdown(entry.content),
});
}
},
};
}

现在,即使使用您的自定义加载器,您也可以像 Markdown 内容存储在您的项目中一样访问 render()<Content />

---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('my-collection', Astro.params.id);
const { Content } = await render(entry);
---
<Content />

有关更多详细信息,请参阅内容加载器文档

禁用实验性响应式图片中的默认样式

当使用实验性响应式图片时,Astro 会应用默认样式以确保图片正确调整大小。在大多数情况下,这正是您想要的——它们以低特异性应用,因此您自己的样式会覆盖它们。

然而,在某些情况下,您可能希望完全禁用这些默认样式。这在使用 Tailwind 4 时特别有用,因为它使用 CSS 层叠层来应用样式,使得覆盖 Astro 的默认样式变得困难。

Astro 5.8.1 添加了一个新的 image.experimentalDefaultStyles 布尔配置选项来应用这些默认样式。它默认为 true,提供当前的响应式图片行为。但是,如果您不想与 Tailwind 4 纠缠,在所有地方设置 !important 样式,您可以简单地在 Astro 配置中禁用此选项

export default {
image: {
experimentalDefaultStyles: false,
},
experimental: {
responsiveImages: true,
},
};

有关更多详细信息,请参阅实验性响应式图片文档

允许适配器抑制关于功能支持的日志

Astro 适配器可以声明它们是否支持某些 Astro 功能,以及该支持是稳定版还是实验版。

在构建过程中,如果网站使用了适配器不支持的功能,Astro 将记录警告或错误。然而,有时适配器可能需要记录更具体的日志消息来帮助用户解决问题。以前这可能会令人困惑,因为这些自定义日志是除了 Astro 生成的日志之外打印的,并且可能看起来与它们相互矛盾。

Astro 5.9 添加了一个选项,允许适配器抑制对不支持功能的日志记录。适配器作者可以添加 suppress: "all"(以同时抑制默认消息和自定义消息)或 suppress: "default"(仅抑制 Astro 的默认消息)

setAdapter({
name: 'my-astro-integration',
supportedAstroFeatures: {
staticOutput: "stable",
hybridOutput: "stable",
sharpImageService: {
support: "limited",
message: "The sharp image service isn't available in the deploy environment, but will be used by prerendered pages on build.",
suppress: "default",
},
}
})

有关更多详细信息,请参阅适配器 API 参考

社区

Astro 核心团队成员是

Ben Holmes , Caleb Jasik , Chris Swithinbank , Emanuele Stoppa , Erika , Florian Lefebvre , Fred Schott , Fuzzy , HiDeoo , Luiz Ferraz , Matt Kane , Matthew Phillips , Nate Moore , Reuben Tier , Sarah Rainsberger , and Yan Thomas

感谢所有其他贡献者,他们通过代码和文档的添加和改进,帮助 Astro 5.9 成为可能,其中包括

, Adriel Martinez, Alexander Niebuhr, Ankur Oberoi, Ariel K, Armand Philippot, Arpan Patel, Ben Limmer, Bjorn Lu, Bugo, Cansin Acarer, Daniel Puscher, Elliot Dong, Hiromasa Fujimori, Hunter Bertoson, Igor Teplostanski, JiPai, Joe, Jonás Perusquía Morales, Junseong Park, Juraj Kapsz, kato takeshi, Kenzo Fachin, knj, liruifengv, Louis Escher, Nin3, Paul Valladares, Reuben Tier, Robin Bühler, Stephen Hendricks, sugardave, Thomas Bonnet, and vivek lokhande