PHP SSL 인증서 오류 해결하기

프리터코더·2025년 5월 28일
0

php 문제 해결

목록 보기
41/79

PHP에서 HTTPS 요청이나 SMTP 연결 시 SSL 인증서 오류는 자주 발생하는 문제입니다. 개발 환경과 운영 환경에서의 안전한 해결 방법을 알아보겠습니다.

1. cURL SSL 인증서 오류 해결

문제: SSL certificate problem: unable to get local issuer certificate 오류

해결책: CA 인증서 번들 파일 설정

function secureCurlRequest($url, $data = null) {
    $ch = curl_init();
    
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_CAINFO => __DIR__ . '/cacert.pem', // CA 번들 파일 경로
        CURLOPT_TIMEOUT => 30,
        CURLOPT_FOLLOWLOCATION => true
    ]);
    
    if ($data) {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    }
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
    if (curl_errno($ch)) {
        throw new Exception('cURL 오류: ' . curl_error($ch));
    }
    
    curl_close($ch);
    return $response;
}
# CA 인증서 번들 다운로드
curl -o cacert.pem https://curl.se/ca/cacert.pem

2. PHPMailer SMTP SSL 오류 해결

문제: SMTP 연결 시 SSL 인증서 검증 실패

해결책: 단계별 SSL 옵션 설정

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;

$mail = new PHPMailer(true);

// 운영 환경용 (권장)
$mail->SMTPOptions = [
    'ssl' => [
        'verify_peer' => true,
        'verify_peer_name' => true,
        'allow_self_signed' => false,
        'cafile' => '/path/to/cacert.pem'
    ]
];

// 개발 환경용 (임시)
if ($_ENV['APP_ENV'] === 'development') {
    $mail->SMTPOptions = [
        'ssl' => [
            'verify_peer' => false,
            'verify_peer_name' => false,
            'allow_self_signed' => true
        ]
    ];
}

$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;

3. 스트림 컨텍스트 SSL 설정

문제: file_get_contents()나 스트림에서 SSL 오류

해결책: 스트림 컨텍스트로 SSL 옵션 설정

function secureFileGetContents($url, $options = []) {
    $defaultOptions = [
        'http' => [
            'method' => 'GET',
            'timeout' => 30,
            'user_agent' => 'Mozilla/5.0 (compatible; PHP)'
        ],
        'ssl' => [
            'verify_peer' => true,
            'verify_peer_name' => true,
            'cafile' => __DIR__ . '/cacert.pem'
        ]
    ];
    
    $context = stream_context_create(array_merge_recursive($defaultOptions, $options));
    
    $result = file_get_contents($url, false, $context);
    
    if ($result === false) {
        throw new Exception("HTTPS 요청 실패: $url");
    }
    
    return $result;
}

// 사용 예시
try {
    $data = secureFileGetContents('https://api.example.com/data');
    echo $data;
} catch (Exception $e) {
    echo "오류: " . $e->getMessage();
}

4. 자체 서명 인증서 환경 대응

문제: 개발/테스트 환경의 자체 서명 인증서

해결책: 환경별 조건부 SSL 설정

class SSLHelper {
    public static function createSecureContext($allowSelfSigned = false) {
        $options = [
            'ssl' => [
                'verify_peer' => true,
                'verify_peer_name' => true,
                'allow_self_signed' => $allowSelfSigned
            ]
        ];
        
        // CA 파일이 존재하면 설정
        $caFile = __DIR__ . '/cacert.pem';
        if (file_exists($caFile)) {
            $options['ssl']['cafile'] = $caFile;
        }
        
        // 개발 환경에서는 검증 완화
        if (defined('DEVELOPMENT') && DEVELOPMENT) {
            $options['ssl']['verify_peer'] = false;
            $options['ssl']['verify_peer_name'] = false;
        }
        
        return stream_context_create($options);
    }
    
    public static function curlWithSSL($url, $allowSelfSigned = false) {
        $ch = curl_init();
        
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => !$allowSelfSigned,
            CURLOPT_SSL_VERIFYHOST => $allowSelfSigned ? 0 : 2
        ]);
        
        if (!$allowSelfSigned && file_exists(__DIR__ . '/cacert.pem')) {
            curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . '/cacert.pem');
        }
        
        return $ch;
    }
}

5. php.ini 전역 SSL 설정

문제: 애플리케이션 전체의 SSL 설정 필요

해결책: php.ini 또는 런타임 설정 조정

// 런타임에 OpenSSL 설정
ini_set('openssl.cafile', '/path/to/cacert.pem');
ini_set('curl.cainfo', '/path/to/cacert.pem');

// 기본 스트림 컨텍스트 설정
$context = stream_context_get_default([
    'ssl' => [
        'verify_peer' => true,
        'verify_peer_name' => true,
        'cafile' => '/path/to/cacert.pem'
    ]
]);

// 설정 확인 함수
function checkSSLConfig() {
    $info = [
        'OpenSSL Version' => OPENSSL_VERSION_TEXT,
        'CA File' => ini_get('openssl.cafile'),
        'cURL CA Info' => ini_get('curl.cainfo'),
        'SSL Support' => extension_loaded('openssl') ? 'Yes' : 'No'
    ];
    
    return $info;
}

print_r(checkSSLConfig());

마무리

SSL 인증서 오류는 보안과 직결되므로 운영 환경에서는 반드시 올바른 인증서 검증을 유지해야 합니다. 개발 환경에서만 임시로 검증을 비활성화하고, CA 번들 파일을 최신 상태로 유지하는 것이 중요합니다.

profile
일용직 개발자. freetercoder@gmail.com

0개의 댓글