React Native安全获取SMTP密码及后端邮件发送的安全实现咨询
安全实现React Native + PHP后端的邮件发送方案
核心安全原则
- 绝对禁止前端处理SMTP凭证:React Native的.env变量会被打包进应用包,完全可逆向获取,任何前端存储/获取密码的方式都无安全性可言。
- 所有邮件逻辑移至后端:前端仅负责上传图片、提交邮件内容,由PHP后端完成SMTP发送。
- 后端接口必须做身份验证:防止非法调用接口发送垃圾邮件或窃取资源。
具体实现步骤
1. 后端接口身份验证(JWT)
使用JWT验证用户身份,确保只有已登录的合法用户能调用邮件接口。
安装依赖
composer require firebase/php-jwt
JWT验证中间件
// jwt-verify.php <?php use Firebase\JWT\JWT; use Firebase\JWT\Key; function verifyJWT($token) { $secretKey = getenv('JWT_SECRET'); // 后端.env存储密钥,绝不暴露 try { $decoded = JWT::decode($token, new Key($secretKey, 'HS256')); return (array)$decoded; } catch (Exception $e) { http_response_code(401); echo json_encode(['error' => '无效的身份令牌']); exit; } } ?>
2. 后端邮件发送接口(支持多图上传)
用PHPMailer处理SMTP发送,同时验证上传文件类型、限制接口调用。
安装依赖
composer require phpmailer/phpmailer
邮件接口代码
// send-email.php <?php require 'vendor/autoload.php'; require 'jwt-verify.php'; // 1. 验证JWT令牌 $token = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; if (empty($token) || !str_starts_with($token, 'Bearer ')) { http_response_code(401); echo json_encode(['error' => '身份令牌缺失']); exit; } $token = substr($token, 7); $user = verifyJWT($token); // 2. 处理图片上传(仅允许图片类型) $attachments = []; if (!empty($_FILES['images'])) { foreach ($_FILES['images']['tmp_name'] as $key => $tmpName) { $fileName = $_FILES['images']['name'][$key]; $fileType = $_FILES['images']['type'][$key]; if (!str_starts_with($fileType, 'image/')) { http_response_code(400); echo json_encode(['error' => `不允许的文件类型:${fileName}`]); exit; } $attachments[] = [ 'path' => $tmpName, 'name' => $fileName, 'type' => $fileType ]; } } // 3. 验证邮件必填参数 $to = $_POST['to'] ?? ''; $subject = $_POST['subject'] ?? ''; $body = $_POST['body'] ?? ''; if (empty($to) || empty($subject)) { http_response_code(400); echo json_encode(['error' => '缺少必填字段']); exit; } // 4. 配置SMTP并发送邮件 $mail = new PHPMailer\PHPMailer\PHPMailer(true); try { // SMTP配置(从后端.env读取) $mail->isSMTP(); $mail->Host = getenv('SMTP_HOST'); $mail->SMTPAuth = true; $mail->Username = getenv('SMTP_USER'); $mail->Password = getenv('SMTP_PASS'); $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS; $mail->Port = 587; // 邮件内容 $mail->setFrom(getenv('SMTP_USER'), '你的应用名称'); $mail->addAddress($to); $mail->isHTML(true); $mail->Subject = $subject; $mail->Body = $body; // 添加图片附件 foreach ($attachments as $att) { $mail->addAttachment($att['path'], $att['name'], PHPMailer\PHPMailer\PHPMailer::ENCODING_BASE64, $att['type']); } $mail->send(); echo json_encode(['success' => true, 'message' => '邮件发送成功']); } catch (Exception $e) { http_response_code(500); echo json_encode(['error' => `邮件发送失败:${$mail->ErrorInfo}`]); } ?>
3. React Native前端调用示例
使用axios提交表单数据,带上JWT令牌,同时上传图片:
import axios from 'axios'; import { Platform } from 'react-native'; import * as ImagePicker from 'react-native-image-picker'; // 假设用户登录后已获取JWT令牌 const authToken = '用户登录返回的JWT字符串'; const sendEmail = async () => { // 选择多张图片 const pickerResult = await ImagePicker.launchImageLibraryAsync({ mediaType: 'photo', allowsMultipleSelection: true, quality: 0.8, }); if (!pickerResult.canceled) { const formData = new FormData(); // 添加邮件参数 formData.append('to', '收件人邮箱@example.com'); formData.append('subject', '测试邮件'); formData.append('body', '<p>这是带图片的测试邮件内容</p>'); // 添加图片文件 pickerResult.assets.forEach((asset, index) => { const uri = Platform.OS === 'android' ? asset.uri : asset.uri.replace('file://', ''); formData.append('images[]', { uri, type: asset.type, name: `image-${index}.${asset.type.split('/')[1]}`, }); }); try { const response = await axios.post('https://你的域名.com/send-email.php', formData, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'multipart/form-data', }, }); console.log('发送成功:', response.data); } catch (error) { console.error('发送失败:', error.response?.data || error.message); } } };
额外安全加固
- 接口限流:在PHP后端添加限流逻辑(比如每个用户每分钟最多调用5次),防止接口滥用。
- 收件人白名单:如果应用仅允许发送到特定域名/邮箱,在后端添加收件人验证。
- 强制HTTPS:所有接口必须使用HTTPS,防止令牌和数据被明文拦截。
- 保护后端.env:将.env文件放在web根目录外,或通过服务器配置禁止直接访问。
内容的提问来源于stack exchange,提问作者Xacoio
相关产品推荐
相关产品推荐

