Markdown सुरक्षा सर्वोत्तम प्रथाएं
Markdown सामग्री को संभालते समय सुरक्षा महत्वपूर्ण है, विशेष रूप से उपयोगकर्ता-जनित सामग्री के साथ। यह गाइड सामान्य कमजोरियों और सुरक्षा रणनीतियों को कवर करती है।
सामान्य सुरक्षा जोखिम
क्रॉस-साइट स्क्रिप्टिंग (XSS)
HTML की अनुमति देने वाले Markdown का शोषण किया जा सकता है:
markdown
<!-- दुर्भावनापूर्ण इनपुट -->
<script>alert('XSS')</script>
<img src=x onerror="alert('XSS')">
<iframe src="javascript:alert('XSS')"></iframe>इंजेक्शन हमले
markdown
<!-- लिंक इंजेक्शन -->
[यहां क्लिक करें](javascript:alert('XSS'))
[दुर्भावनापूर्ण](data:text/html,<script>alert('XSS')</script>)
<!-- छवि इंजेक्शन -->
)सैनिटाइजेशन
HTML सैनिटाइजेशन
javascript
const DOMPurify = require('isomorphic-dompurify');
function renderSafe(markdown) {
const html = md.render(markdown);
return DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong', 'a', 'ul', 'ol', 'li'],
ALLOWED_ATTR: ['href', 'title']
});
}Markdown पार्सर कॉन्फ़िगर करें
javascript
const md = require('markdown-it')({
html: false, // स्रोत में HTML टैग अक्षम करें
linkify: true, // URL को स्वचालित रूप से कन्वर्ट करें
typographer: true
});
// खतरनाक प्रोटोकॉल अक्षम करें
md.validateLink = function (url) {
const allowedProtocols = /^(https?|ftp|mailto):/i;
return allowedProtocols.test(url);
};कंटेंट सिक्योरिटी पॉलिसी (CSP)
मूल CSP हेडर
html
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;">सख्त CSP
javascript
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy', [
"default-src 'self'",
"script-src 'self'",
"style-src 'self'",
"img-src 'self' https:",
"font-src 'self'",
"connect-src 'self'",
"frame-ancestors 'none'"
].join('; '));
next();
});इनपुट सत्यापन
लंबाई सीमा
javascript
function validateMarkdown(content) {
const MAX_LENGTH = 50000;
if (content.length > MAX_LENGTH) {
throw new Error('सामग्री बहुत लंबी है');
}
return content;
}सामग्री फ़िल्टरिंग
javascript
function filterMarkdown(content) {
// संभावित खतरनाक पैटर्न हटाएं
return content
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
.replace(/javascript:/gi, '')
.replace(/on\w+\s*=/gi, '');
}उपयोगकर्ता-जनित सामग्री
व्हाइटलिस्ट दृष्टिकोण
javascript
const allowedTags = {
p: [],
strong: [],
em: [],
a: ['href', 'title'],
ul: [],
ol: [],
li: [],
h1: [],
h2: [],
h3: [],
code: [],
pre: []
};
function sanitizeUserContent(html) {
return DOMPurify.sanitize(html, {
ALLOWED_TAGS: Object.keys(allowedTags),
ALLOWED_ATTR: Object.values(allowedTags).flat()
});
}रेट लिमिटिंग
javascript
const rateLimit = require('express-rate-limit');
const markdownLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 मिनट
max: 100, // प्रत्येक IP को windowMs प्रति 100 अनुरोधों की सीमा
message: 'बहुत अधिक सबमिशन, कृपया बाद में पुनः प्रयास करें।'
});
app.post('/api/markdown', markdownLimiter, (req, res) => {
// markdown सबमिशन संभालें
});फ़ाइल अपलोड सुरक्षा
सत्यापन
javascript
const allowedExtensions = ['.md', '.markdown', '.txt'];
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
function validateFile(file) {
const ext = path.extname(file.name).toLowerCase();
if (!allowedExtensions.includes(ext)) {
throw new Error('अमान्य फ़ाइल प्रकार');
}
if (file.size > MAX_FILE_SIZE) {
throw new Error('फ़ाइल बहुत बड़ी है');
}
return true;
}वायरस स्कैनिंग
javascript
const ClamScan = require('clamscan');
async function scanFile(filePath) {
const clamscan = await new ClamScan().init();
const { isInfected, viruses } = await clamscan.isInfected(filePath);
if (isInfected) {
throw new Error(`वायरस का पता चला: ${viruses.join(', ')}`);
}
return true;
}प्रमाणीकरण और प्राधिकरण
एक्सेस नियंत्रण
javascript
function checkPermissions(user, action) {
const permissions = {
admin: ['read', 'write', 'delete'],
editor: ['read', 'write'],
viewer: ['read']
};
return permissions[user.role]?.includes(action);
}
app.post('/api/markdown', (req, res) => {
if (!checkPermissions(req.user, 'write')) {
return res.status(403).json({ error: 'निषिद्ध' });
}
// markdown प्रोसेस करें
});CSRF सुरक्षा
javascript
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
app.post('/api/markdown', csrfProtection, (req, res) => {
// सुरक्षित एंडपॉइंट
});सुरक्षित स्टोरेज
एन्क्रिप्शन
javascript
const crypto = require('crypto');
function encryptContent(content, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update(content, 'utf8', 'hex');
encrypted += cipher.final('hex');
return { encrypted, iv: iv.toString('hex') };
}
function decryptContent(encrypted, iv, key) {
const decipher = crypto.createDecipheriv('aes-256-cbc', key, Buffer.from(iv, 'hex'));
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}SQL इंजेक्शन रोकथाम
javascript
// पैरामीटराइज्ड क्वेरी का उपयोग करें
const query = 'INSERT INTO posts (title, content) VALUES (?, ?)';
db.execute(query, [title, content]);
// कभी भी उपयोगकर्ता इनपुट को कनकेटनेट न करें
// ❌ const query = `INSERT INTO posts VALUES ('${userInput}')`;API सुरक्षा
API रेट लिमिटिंग
javascript
const slowDown = require('express-slow-down');
const speedLimiter = slowDown({
windowMs: 15 * 60 * 1000,
delayAfter: 100,
delayMs: 500
});
app.use('/api/', speedLimiter);API कुंजी सत्यापन
javascript
function validateApiKey(req, res, next) {
const apiKey = req.headers['x-api-key'];
if (!apiKey || !isValidApiKey(apiKey)) {
return res.status(401).json({ error: 'अमान्य API कुंजी' });
}
next();
}सुरक्षित Markdown पार्सिंग
सुरक्षित पार्सर कॉन्फ़िगरेशन
javascript
const md = require('markdown-it')({
html: false, // HTML अक्षम करें
xhtmlOut: true, // XHTML आउटपुट का उपयोग करें
breaks: false, // \n को <br> में न बदलें
linkify: true, // URL को स्वचालित रूप से कन्वर्ट करें
typographer: false // स्थिरता के लिए स्मार्ट कोट्स अक्षम करें
});
// कस्टम लिंक सत्यापन
md.validateLink = (url) => {
const safe = /^(https?|mailto):/i.test(url);
return safe;
};
// रेंडर फ़ंक्शन
md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
const token = tokens[idx];
const hrefIndex = token.attrIndex('href');
if (hrefIndex >= 0) {
const url = token.attrs[hrefIndex][1];
// सुरक्षा विशेषताएं जोड़ें
token.attrPush(['rel', 'noopener noreferrer']);
// बाहरी लिंक्स के लिए target="_blank" जोड़ें
if (/^https?:/.test(url)) {
token.attrPush(['target', '_blank']);
}
}
return self.renderToken(tokens, idx, options);
};सुरक्षा हेडर्स
व्यापक सुरक्षा हेडर्स
javascript
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
frameguard: {
action: 'deny'
},
noSniff: true,
xssFilter: true
}));सुरक्षा चेकलिस्ट
markdown
## Markdown सुरक्षा चेकलिस्ट
- [ ] Markdown पार्सर में HTML अक्षम करें
- [ ] सभी HTML आउटपुट को सैनिटाइज करें
- [ ] URL को सत्यापित और व्हाइटलिस्ट करें
- [ ] कंटेंट सिक्योरिटी पॉलिसी लागू करें
- [ ] पैरामीटराइज्ड क्वेरी का उपयोग करें
- [ ] फ़ाइल अपलोड को सत्यापित करें
- [ ] फ़ाइल आकार सीमा निर्धारित करें
- [ ] रेट लिमिटिंग लागू करें
- [ ] CSRF सुरक्षा का उपयोग करें
- [ ] संवेदनशील सामग्री को एन्क्रिप्ट करें
- [ ] API कुंजियों को सत्यापित करें
- [ ] सुरक्षित हेडर्स सेट करें
- [ ] सुरक्षा घटनाओं को लॉग करें
- [ ] नियमित सुरक्षा ऑडिट
- [ ] डिपेंडेंसी को अपडेटेड रखेंमॉनिटरिंग और लॉगिंग
सुरक्षा घटना लॉगिंग
javascript
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'security.log' })
]
});
function logSecurityEvent(event, details) {
logger.warn({
timestamp: new Date().toISOString(),
event,
details,
ip: details.ip,
user: details.user
});
}निष्कर्ष
सुरक्षा एक चल रही प्रक्रिया है। नियमित रूप से अपनी सुरक्षा उपायों की समीक्षा और अपडेट करें, डिपेंडेंसी को अपडेटेड रखें, और नई कमजोरियों के बारे में सूचित रहें।