From de074f39fce8b4c15b94e37421f9eb9a525d46f7 Mon Sep 17 00:00:00 2001
From: zhuba-Ahhh <3477826311@qq.com>
Date: Wed, 28 Aug 2024 13:56:12 +0800
Subject: [PATCH] feat: :sparkles: wordCount
---
src/app/blog/[id]/AnimatedBlogPost.tsx | 8 +-
src/app/blog/[id]/BlogHeader.tsx | 11 +-
src/app/blog/[id]/page.tsx | 3 +-
src/data/ts/14.ts | 152 ++++++++++++-------------
src/utils/blogHelpers.ts | 4 +-
5 files changed, 95 insertions(+), 83 deletions(-)
diff --git a/src/app/blog/[id]/AnimatedBlogPost.tsx b/src/app/blog/[id]/AnimatedBlogPost.tsx
index d611502..1dc20d7 100644
--- a/src/app/blog/[id]/AnimatedBlogPost.tsx
+++ b/src/app/blog/[id]/AnimatedBlogPost.tsx
@@ -16,6 +16,7 @@ interface AnimatedBlogPostProps {
post: BlogPost;
headings: Heading[];
readingTime: number;
+ wordCount: number;
relatedPosts: BlogPost[];
prevPost?: BlogPost;
nextPost?: BlogPost;
@@ -26,6 +27,7 @@ export default function AnimatedBlogPost({
prevPost,
nextPost,
headings,
+ wordCount,
readingTime,
relatedPosts,
}: AnimatedBlogPostProps) {
@@ -53,7 +55,11 @@ export default function AnimatedBlogPost({
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.5, delay: 0.3 }}
>
-
+
@@ -20,8 +25,8 @@ export default function BlogHeader({ post, readingTime }: BlogHeaderProps) {
{author}
|
-
- 预计阅读时间: {readingTime} 分钟
+ 共 {wordCount} 字,预计阅读时间:{" "}
+ {readingTime} 分钟
{coverImage && (
diff --git a/src/app/blog/[id]/page.tsx b/src/app/blog/[id]/page.tsx
index 5858edf..6254e64 100644
--- a/src/app/blog/[id]/page.tsx
+++ b/src/app/blog/[id]/page.tsx
@@ -29,7 +29,7 @@ export default async function BlogPost({ params }: BlogPostParams) {
}
const headings: Heading[] = extractHeadings(post.content);
- const readingTime: number = estimateReadingTime(post.content);
+ const [readingTime, wordCount] = estimateReadingTime(post.content);
const relatedPosts: BlogPost[] = blogPosts
.filter(
@@ -48,6 +48,7 @@ export default async function BlogPost({ params }: BlogPostParams) {
post={post}
headings={headings}
readingTime={readingTime}
+ wordCount={wordCount}
relatedPosts={relatedPosts}
prevPost={prevPost}
nextPost={nextPost}
diff --git a/src/data/ts/14.ts b/src/data/ts/14.ts
index 189adad..fe74f87 100644
--- a/src/data/ts/14.ts
+++ b/src/data/ts/14.ts
@@ -7,124 +7,124 @@ export const content14 = `
跨站脚本攻击是最常见且危险的Web安全威胁之一。以下是防御XSS的关键策略:
-1. 内容安全策略 (CSP):
- - 实施严格的CSP: 限制可执行脚本、样式和其他资源的来源。
- - 示例: \`Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com\`
-
-2. 输入验证与输出编码:
- - 对所有用户输入进行严格验证和过滤。
- - 在输出到HTML、JavaScript、CSS或URL时,使用适当的编码函数。
- - 使用成熟的库如DOMPurify进行HTML净化。
-
-3. HttpOnly和Secure标志:
- - 为敏感Cookie设置HttpOnly标志,防止JavaScript访问。
- - 使用Secure标志确保Cookie仅通过HTTPS传输。
-
-4. X-XSS-Protection头:
- - 启用浏览器内置的XSS过滤器: \`X-XSS-Protection: 1; mode=block\`
+1.内容安全策略 (CSP):
+ - 实施严格的CSP: 限制可执行脚本、样式和其他资源的来源。
+ - 示例: \`Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com\`
+
+2.输入验证与输出编码:
+ - 对所有用户输入进行严格验证和过滤。
+ - 在输出到HTML、JavaScript、CSS或URL时,使用适当的编码函数。
+ - 使用成熟的库如DOMPurify进行HTML净化。
+
+3.HttpOnly和Secure标志:
+ - 为敏感Cookie设置HttpOnly标志,防止JavaScript访问。
+ - 使用Secure标志确保Cookie仅通过HTTPS传输。
+
+4.X-XSS-Protection头:
+ - 启用浏览器内置的XSS过滤器: \`X-XSS-Protection: 1; mode=block\`
## CSRF (跨站请求伪造) 保护
CSRF攻击利用用户的已认证会话执行未授权操作。防御措施包括:
-1. CSRF令牌:
- - 实现同步令牌模式: 在表单中包含随机生成的令牌。
- - 双重提交Cookie: 将令牌同时存储在Cookie和请求参数中。
+1.CSRF令牌:
+ - 实现同步令牌模式: 在表单中包含随机生成的令牌。
+ - 双重提交Cookie: 将令牌同时存储在Cookie和请求参数中。
-2. SameSite Cookie属性:
- - 设置\`SameSite=Strict\`或\`SameSite=Lax\`限制跨站Cookie传输。
+2.SameSite Cookie属性:
+ - 设置\`SameSite=Strict\`或\`SameSite=Lax\`限制跨站Cookie传输。
-3. 自定义请求头:
- - 为AJAX请求添加自定义头,如\`X-Requested-With: XMLHttpRequest\`。
+3.自定义请求头:
+ - 为AJAX请求添加自定义头,如\`X-Requested-With: XMLHttpRequest\`。
-4. 验证Referer和Origin:
- - 检查请求的Referer或Origin头,确保请求来自合法来源。
+4.验证Referer和Origin:
+ - 检查请求的Referer或Origin头,确保请求来自合法来源。
## 安全的第三方库管理
第三方库可能引入安全漏洞,需要谨慎管理:
-1. 依赖审计:
- - 使用npm audit、yarn audit或Snyk定期检查依赖。
- - 集成到CI/CD流程中,自动化漏洞检测。
+1.依赖审计:
+ - 使用npm audit、yarn audit或Snyk定期检查依赖。
+ - 集成到CI/CD流程中,自动化漏洞检测。
-2. 版本锁定:
- - 使用package-lock.json或yarn.lock锁定依赖版本。
- - 定期更新并测试最新的安全补丁。
+2.版本锁定:
+ - 使用package-lock.json或yarn.lock锁定依赖版本。
+ - 定期更新并测试最新的安全补丁。
-3. 子资源完整性 (SRI):
- - 为CDN资源添加integrity属性,确保内容未被篡改。
- - 示例: \`\`
+3.子资源完整性 (SRI):
+ - 为CDN资源添加integrity属性,确保内容未被篡改。
+ - 示例: \`\`
## HTTPS 实施
HTTPS对于保护数据传输至关重要:
-1. 全站HTTPS:
- - 将所有HTTP流量重定向到HTTPS。
- - 使用HSTS (HTTP严格传输安全) 头强制HTTPS连接。
+1.全站HTTPS:
+ - 将所有HTTP流量重定向到HTTPS。
+ - 使用HSTS (HTTP严格传输安全) 头强制HTTPS连接。
-2. 正确配置TLS:
- - 使用强加密套件,禁用不安全的协议版本。
- - 定期更新和轮换SSL/TLS证书。
+2.正确配置TLS:
+ - 使用强加密套件,禁用不安全的协议版本。
+ - 定期更新和轮换SSL/TLS证书。
-3. 证书透明度 (CT) 日志:
- - 监控CT日志,及时发现针对您域名的可疑证书颁发。
+3.证书透明度 (CT) 日志:
+ - 监控CT日志,及时发现针对您域名的可疑证书颁发。
## 安全的客户端存储
正确使用客户端存储机制对保护用户数据至关重要:
-1. 敏感数据加密:
- - 使用Web Crypto API进行客户端加密。
- - 避免在localStorage中存储敏感信息。
+1.敏感数据加密:
+ - 使用Web Crypto API进行客户端加密。
+ - 避免在localStorage中存储敏感信息。
-2. IndexedDB安全:
- - 实施适当的访问控制和数据隔离。
- - 考虑对存储的数据进行加密。
+2.IndexedDB安全:
+ - 实施适当的访问控制和数据隔离。
+ - 考虑对存储的数据进行加密。
-3. 安全的会话管理:
- - 使用服务器端会话存储敏感数据。
- - 实现会话超时和安全的注销机制。
+3.安全的会话管理:
+ - 使用服务器端会话存储敏感数据。
+ - 实现会话超时和安全的注销机制。
## 高级安全实践
-1. 子域隔离:
- - 将不同功能部署到不同子域,限制潜在攻击面。
+1.子域隔离:
+ - 将不同功能部署到不同子域,限制潜在攻击面。
-2. 浏览器指纹防护:
- - 最小化暴露给第三方脚本的信息。
- - 考虑使用隐私保护技术如Tor浏览器。
+2.浏览器指纹防护:
+ - 最小化暴露给第三方脚本的信息。
+ - 考虑使用隐私保护技术如Tor浏览器。
-3. WebSocket安全:
- - 实施适当的身份验证和授权机制。
- - 使用wss://协议确保加密传输。
+3.WebSocket安全:
+ - 实施适当的身份验证和授权机制。
+ - 使用wss://协议确保加密传输。
-4. 防御点击劫持:
- - 使用X-Frame-Options或CSP frame-ancestors指令。
+4.防御点击劫持:
+ - 使用X-Frame-Options或CSP frame-ancestors指令。
-5. API安全:
- - 实施速率限制和请求节流。
- - 使用OAuth 2.0和OpenID Connect进行安全授权。
+5.API安全:
+ - 实施速率限制和请求节流。
+ - 使用OAuth 2.0和OpenID Connect进行安全授权。
## 持续安全实践
-1. 安全编码规范:
- - 制定并执行安全编码指南。
- - 进行定期的代码审查和安全培训。
+1.安全编码规范:
+ - 制定并执行安全编码指南。
+ - 进行定期的代码审查和安全培训。
-2. 漏洞赏金计划:
- - 考虑建立漏洞赏金项目,鼓励外部研究人员报告安全问题。
+2.漏洞赏金计划:
+ - 考虑建立漏洞赏金项目,鼓励外部研究人员报告安全问题。
-3. 安全监控和响应:
- - 实施日志记录和监控系统。
- - 制定并演练安全事件响应计划。
+3.安全监控和响应:
+ - 实施日志记录和监控系统。
+ - 制定并演练安全事件响应计划。
-4. 定期安全评估:
- - 进行渗透测试和安全审计。
- - 使用自动化工具进行持续的安全扫描。
+4.定期安全评估:
+ - 进行渗透测试和安全审计。
+ - 使用自动化工具进行持续的安全扫描。
结论:
前端安全是一个动态且持续的过程,需要开发者保持警惕并不断学习。通过实施这些最佳实践,您可以显著提高Web应用的安全性,保护用户数据和隐私。记住,安全不是一次性的工作,而是需要持续关注和改进的领域。让我们共同努力,为用户创造一个更安全的网络环境!
diff --git a/src/utils/blogHelpers.ts b/src/utils/blogHelpers.ts
index ce1c1e9..5158abc 100644
--- a/src/utils/blogHelpers.ts
+++ b/src/utils/blogHelpers.ts
@@ -28,10 +28,10 @@ export function extractHeadings(content: string) {
return headings;
}
-export function estimateReadingTime(content: string): number {
+export function estimateReadingTime(content: string): number[] {
const wordsPerMinute = 200;
const wordCount = content.split(/\s+/).length;
- return Math.ceil(wordCount / wordsPerMinute);
+ return [Math.ceil(wordCount / wordsPerMinute), wordCount];
}
export function useExtractHeadings(content: string) {