diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..f3b05e6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,254 @@ +# Security Implementation Guide for NeoNest + +This document outlines the comprehensive security measures implemented to protect NeoNest users and data. + +## 🔒 Security Features Implemented + +### 1. Cross-Site Request Forgery (CSRF) Protection +- **Location**: `lib/csrf.js` +- **Implementation**: Token-based CSRF protection for all state-changing requests +- **Usage**: Automatically applied via security middleware + +### 2. Cross-Site Scripting (XSS) Prevention +- **Components Fixed**: + - `app/components/TextToSpeech.js` + - `app/components/SpeechRecognition.js` +- **Implementation**: Input sanitization and output encoding +- **Protection**: Prevents malicious script injection + +### 3. Server-Side Request Forgery (SSRF) Prevention +- **Location**: `lib/urlValidator.js` +- **Implementation**: URL validation with allowlist approach +- **Features**: + - Domain allowlisting + - Private IP range blocking + - Protocol validation (HTTPS only) + +### 4. Input Validation & Sanitization +- **Location**: `lib/auth.js`, `lib/security.js` +- **Implementation**: Comprehensive input validation +- **Features**: + - Type checking + - Length validation + - XSS pattern detection + - SQL injection prevention + +### 5. Rate Limiting +- **Location**: `lib/security.js` +- **Implementation**: In-memory rate limiting +- **Configuration**: 60 requests per minute per IP +- **Block Duration**: 15 minutes for violators + +### 6. Enhanced Authentication +- **Location**: `app/api/auth/login/route.js` +- **Improvements**: + - Generic error messages (security through obscurity) + - Enhanced input validation + - Secure JWT generation + - Password data exclusion from responses + +### 7. Security Headers +- **Implementation**: Added to all API responses +- **Headers**: + - `X-Content-Type-Options: nosniff` + - `X-Frame-Options: DENY` + - `X-XSS-Protection: 1; mode=block` + +## 🛠 How to Use Security Features + +### For API Routes + +```javascript +import { withSecurity } from '@/lib/security'; + +async function myAPIHandler(req) { + // Your API logic here + return Response.json({ success: true }); +} + +// Apply security middleware +export const POST = withSecurity(myAPIHandler); +``` + +### For Client-Side Requests + +```javascript +import { secureFetch } from '@/lib/clientSecurity'; + +// Secure API call with automatic CSRF protection +const response = await secureFetch('/api/data', { + method: 'POST', + body: JSON.stringify({ data: 'example' }) +}); +``` + +### Input Validation + +```javascript +import { validateAndSanitizeInput } from '@/lib/security'; + +// Validate user input +if (!validateAndSanitizeInput(userInput, 'string', 100)) { + throw new Error('Invalid input'); +} +``` + +### URL Validation for External Requests + +```javascript +import { safeFetch } from '@/lib/urlValidator'; + +// Safe external API call +try { + const response = await safeFetch('https://api.example.com/data'); +} catch (error) { + console.error('URL validation failed:', error.message); +} +``` + +## 🌐 Internationalization (i18n) Support + +### Setup +- **Location**: `lib/i18n.js` +- **Supported Languages**: English, Spanish, Hindi +- **Usage**: + +```javascript +import { t, setLanguage } from '@/lib/i18n'; + +// Set language +setLanguage('es'); + +// Translate text +const translatedText = t('login', 'Login'); +``` + +### Adding New Languages + +1. Edit `lib/i18n.js` +2. Add translations to the `translations` object +3. Update `getAvailableLanguages()` function + +## 🔧 Configuration + +### Environment Variables Required + +```env +JWT_SECRET=your-super-secret-jwt-key-here +MONGODB_URI=your-mongodb-connection-string +``` + +### Security Configuration + +The security middleware can be configured in `lib/security.js`: + +```javascript +// Rate limiting configuration +this.maxRequestsPerMinute = 60; +this.blockDuration = 15 * 60 * 1000; // 15 minutes + +// Allowed domains for external requests +const ALLOWED_DOMAINS = [ + 'api.openai.com', + 'generativelanguage.googleapis.com', + 'cloudinary.com' +]; +``` + +## 🚨 Security Best Practices + +### 1. Input Handling +- Always validate and sanitize user inputs +- Use parameterized queries for database operations +- Implement proper error handling + +### 2. Authentication +- Use strong JWT secrets +- Implement proper session management +- Add logout functionality that clears tokens + +### 3. API Security +- Apply security middleware to all API routes +- Use HTTPS in production +- Implement proper CORS policies + +### 4. Client-Side Security +- Use the provided `secureFetch` wrapper +- Sanitize user inputs before display +- Validate forms on both client and server side + +## 🔍 Security Testing + +### Manual Testing Checklist + +- [ ] CSRF protection works for POST/PUT/DELETE requests +- [ ] XSS attempts are blocked and sanitized +- [ ] Rate limiting triggers after 60 requests/minute +- [ ] Invalid URLs are rejected by SSRF protection +- [ ] Authentication requires valid JWT tokens +- [ ] Input validation rejects malicious payloads + +### Automated Testing + +Consider implementing: +- Unit tests for security functions +- Integration tests for API endpoints +- Security scanning tools (OWASP ZAP, etc.) + +## 📋 Security Incident Response + +### If a Security Issue is Discovered + +1. **Immediate Response**: + - Document the issue + - Assess the impact + - Implement temporary mitigation + +2. **Investigation**: + - Check logs for exploitation attempts + - Identify affected users/data + - Determine root cause + +3. **Resolution**: + - Apply security patches + - Update security measures + - Notify affected users if necessary + +4. **Prevention**: + - Update security documentation + - Improve testing procedures + - Conduct security review + +## 🔄 Regular Security Maintenance + +### Monthly Tasks +- Review and update dependencies +- Check for new security vulnerabilities +- Update security configurations + +### Quarterly Tasks +- Conduct security audits +- Review access controls +- Update security documentation + +### Annual Tasks +- Comprehensive penetration testing +- Security training for developers +- Review and update security policies + +## 📞 Security Contact + +For security-related issues or questions: +- Create a GitHub issue with the `security` label +- Follow responsible disclosure practices +- Provide detailed information about vulnerabilities + +## 🔗 Additional Resources + +- [OWASP Top 10](https://owasp.org/www-project-top-ten/) +- [Next.js Security Guidelines](https://nextjs.org/docs/advanced-features/security-headers) +- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/) + +--- + +**Note**: This security implementation provides a strong foundation, but security is an ongoing process. Regular updates and monitoring are essential for maintaining protection against evolving threats. \ No newline at end of file diff --git a/app/Essentials/page.js b/app/Essentials/page.js index a6755a7..8b37bbf 100644 --- a/app/Essentials/page.js +++ b/app/Essentials/page.js @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card"; import { Button } from "../components/ui/Button"; import Input from "../components/ui/Input"; @@ -47,7 +47,7 @@ export default function Page() { }; // Fetch inventory from API - const fetchInventory = async () => { + const fetchInventory = useCallback(async () => { try { setIsInventoryLoading(true); const token = getAuthToken(); @@ -70,14 +70,14 @@ export default function Page() { } finally { setIsInventoryLoading(false); } - }; + }, []); useEffect(() => { document.title = "Essentials | NeoNest"; if (isAuth) { fetchInventory(); } - }, [isAuth]); + }, [isAuth, fetchInventory]); // Add new item const addItem = async () => { @@ -515,7 +515,7 @@ export default function Page() { - {item.notes &&

"{item.notes}"

} + {item.notes &&

"{item.notes}"

}
{index === currentTrackIndex && isPlaying && (
- - - + + +
)} diff --git a/app/Medical/page.js b/app/Medical/page.js index 4fb70c8..8ac5e34 100644 --- a/app/Medical/page.js +++ b/app/Medical/page.js @@ -1,5 +1,5 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback } from "react"; import axios from "axios"; import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card"; import Input from "../components/ui/Input"; @@ -74,9 +74,9 @@ export default function VaccineTracker({ babyId }) { fetchVaccines(); // fetchBabyBirthDate() } - }, [isAuth]); + }, [isAuth, fetchVaccines]); - const fetchVaccines = async () => { + const fetchVaccines = useCallback(async () => { try { const token = getAuthToken(); const res = await axios.get("/api/vaccine", { @@ -86,7 +86,7 @@ export default function VaccineTracker({ babyId }) { } catch (error) { console.error("Error fetching vaccines:", error); } - }; + }, []); const initializeStandardSchedule = async () => { if (!babyBirthDate) return; @@ -207,7 +207,7 @@ export default function VaccineTracker({ babyId }) {

Medical Records: Vaccines & Important Contacts

-

Keep track of your baby's vaccination schedule and essential medical contacts for quick access.

+

Keep track of your baby's vaccination schedule and essential medical contacts for quick access.

diff --git a/app/Resources/page.js b/app/Resources/page.js index 0b32f38..55073fb 100644 --- a/app/Resources/page.js +++ b/app/Resources/page.js @@ -1,6 +1,7 @@ "use client"; import React, { useState, useEffect } from "react"; +import Image from "next/image"; import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card"; import { Button } from "../components/ui/Button"; import Badge from "../components/ui/Badge"; @@ -407,7 +408,13 @@ export default function Resources() { {/* Thumbnail */} {article.thumbnail && (
- {article.title} + {article.title}
)} diff --git a/app/Sleep/page.js b/app/Sleep/page.js index baace94..a5c5154 100644 --- a/app/Sleep/page.js +++ b/app/Sleep/page.js @@ -1,7 +1,6 @@ "use client"; import { useState, useEffect } from "react"; -import axios from "axios"; import { Plus, Clock, Moon, Edit, Trash2, Calendar, Save } from "lucide-react"; import Input from "../components/ui/Input"; import { Button } from "../components/ui/Button"; @@ -9,6 +8,8 @@ import Badge from "../components/ui/Badge"; import Sleeptips from "../components/Sleeptips"; import { useAuth } from "../context/AuthContext"; import LoginPrompt from "../components/LoginPrompt"; +import { secureFetch } from "../../lib/clientSecurity"; +import { t } from "../../lib/i18n"; export default function Page() { const { isAuth, token } = useAuth(); @@ -24,15 +25,16 @@ export default function Page() { notes: "", }); - const headers = token ? { Authorization: `Bearer ${token}` } : {}; + // Headers are now handled by secureFetch useEffect(() => { document.title = "Sleep | NeoNest"; if (isAuth) { const fetchLogs = async () => { try { - const res = await axios.get("/api/sleep", { headers }); - setSchedules(res.data); + const res = await secureFetch("/api/sleep", { method: 'GET' }); + const data = await res.json(); + setSchedules(data); } catch (err) { console.error("Failed to fetch logs:", err); } finally { @@ -51,8 +53,12 @@ export default function Page() { babyName: "YourBaby", }; try { - const res = await axios.post("/api/sleep", item, { headers }); - setSchedules([...schedules, res.data]); + const res = await secureFetch("/api/sleep", { + method: 'POST', + body: JSON.stringify(item) + }); + const data = await res.json(); + setSchedules([...schedules, data]); resetForm(); } catch (err) { console.error("Failed to add:", err); @@ -61,8 +67,12 @@ export default function Page() { const updateSchedule = async (id, updated) => { try { - const res = await axios.patch(`/api/sleep/${id}`, updated, { headers }); - setSchedules(schedules.map((s) => (s._id === id ? res.data : s))); + const res = await secureFetch(`/api/sleep/${id}`, { + method: 'PATCH', + body: JSON.stringify(updated) + }); + const data = await res.json(); + setSchedules(schedules.map((s) => (s._id === id ? data : s))); setEditingSchedule(null); } catch (err) { console.error("Update failed:", err); @@ -71,7 +81,7 @@ export default function Page() { const deleteSchedule = async (id) => { try { - await axios.delete(`/api/sleep/${id}`, { headers }); + await secureFetch(`/api/sleep/${id}`, { method: 'DELETE' }); setSchedules(schedules.filter((s) => s._id !== id)); } catch (err) { console.error("Delete failed:", err); @@ -144,7 +154,7 @@ export default function Page() {
- +
- +
- +

- Today's Sleep Schedule + Today's Sleep Schedule {todaySchedules.length} entries

@@ -286,7 +296,7 @@ export default function Page() { {moodEmoji(s.mood)} {s.mood} )} - {s.notes && "{s.notes}"} + {s.notes && "{s.notes}"}

- Supporting parents through their baby's first year with expert guidance, AI tools, and a loving community. + Supporting parents through their baby's first year with expert guidance, AI tools, and a loving community.

Happy baby, Happy you! diff --git a/app/components/ImportantContacts .js b/app/components/ImportantContacts .js index d13e2b0..968a0ca 100644 --- a/app/components/ImportantContacts .js +++ b/app/components/ImportantContacts .js @@ -186,7 +186,7 @@ export default function ImportantContacts() { )}

- {contact.description &&

"{contact.description}"

} + {contact.description &&

"{contact.description}"

}
diff --git a/app/components/LoginPrompt.js b/app/components/LoginPrompt.js index 9a6400b..50b067e 100644 --- a/app/components/LoginPrompt.js +++ b/app/components/LoginPrompt.js @@ -51,11 +51,11 @@ export default function LoginPrompt({ sectionName = "this section" }) {

- Access Your Baby's Personalized Features + Access Your Baby's Personalized Features

- Please log in to access your baby's personalized {sectionName} and track their progress with our comprehensive tools. + Please log in to access your baby's personalized {sectionName} and track their progress with our comprehensive tools.

@@ -92,7 +92,7 @@ export default function LoginPrompt({ sectionName = "this section" }) {

- Don't have an account?{" "} + Don't have an account?{" "}