[Python] 신뢰할 수 있는 접속URL을 자동으로 등록해 주는 Python 코드
브라우저에 등록된 Experiments 중 “Insecure origins treated as secure(unsafely-treat-insecure-origin-as-secure)”에 신뢰할 수 있는 접속URL을 자동으로 등록해 주는 Python 코드입니다. pyinstaller 패키지를 설치한 후 py -m PyInstaller -F .\register_secure_url.py를 실행하여 파이션 실행파일을 생성해서 배포하면 편리하게 신뢰할 수 있는 URL을 자동 등록할 수 있습니다.
파일명: register_secure_url.py
import os
import json
from pathlib import Path
import subprocess
import time
import re
import datetime
import sys
def terminate_browser(browser_name: str):
"""
지정된 브라우저 프로세스를 강제 종료합니다.
"""
browser_name = browser_name.lower()
if browser_name == 'chrome':
process_name = 'chrome.exe'
elif browser_name == 'edge':
process_name = 'msedge.exe'
else:
print(f"에러: 알 수 없는 브라우저 '{browser_name}'")
return False
command = f'taskkill /f /im {process_name}'
try:
# shell=True는 Windows 명령어를 실행할 수 있게 해줍니다.
# check=True는 명령어 실행 실패 시 예외를 발생시킵니다.
subprocess.run(command, shell=True, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
encoding='cp949') # Windows에서 한글 출력을 위해 cp949 인코딩 사용
print(f"{browser_name} 프로세스를 성공적으로 강제 종료했습니다.")
time.sleep(1) # 프로세스가 완전히 종료될 시간을 잠시 대기
return True
except subprocess.CalledProcessError as e:
# 프로세스가 실행 중이 아니었을 경우 (오류가 아닐 수 있음)
if re.search(r".*프로세스.*찾을 수 없습니다", e.stderr.strip()):
print(f"{browser_name} 프로세스는 실행 중이지 않습니다.")
return True # 종료할 프로세스가 없었으므로 성공으로 간주
else:
print(f"{browser_name} 종료 실패: {e.stderr.strip()}")
return False
except Exception as e:
print(f"예상치 못한 오류: {e}")
return False
def register_secure_url(browser_name: str, new_url: str):
"""
Chrome 또는 Edge의 Local State 파일에서 지정된 실험 URL 값을 읽고 씁니다.
"""
if not terminate_browser(browser_name):
return False
# 1. 파일 경로 설정
appdata_local_path = Path(os.getenv('LOCALAPPDATA'))
if browser_name.lower() == 'chrome':
file_path = appdata_local_path / "Google" / "Chrome" / "User Data" / "Local State"
elif browser_name.lower() == 'edge':
file_path = appdata_local_path / "Microsoft" / "Edge" / "User Data" / "Local State"
else:
print("에러: 'chrome' 또는 'edge'를 지정해주세요.")
return False
# 2. 파일 존재 확인
if not file_path.exists():
print(f"에러: {browser_name}의 Local State 파일이 존재하지 않습니다. 경로: {file_path}")
return False
# 3. JSON 파일 읽기 및 쓰기
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
key_browser = "browser"
key_enable_labs = "enabled_labs_experiments"
key_origin_lists = "enabled_labs_experiments_origin_lists"
key_as_secure = "unsafely-treat-insecure-origin-as-secure"
# JSON 딕셔너리 계층 구조에 따라 값에 접근합니다.
# data["키1"]["키2"]["찾는_키"]
old_url = data.get(key_browser, {}) \
.get(key_origin_lists, {}) \
.get(key_as_secure)
# 1단계 키: browser
if key_browser not in data:
data[key_browser] = {} # 키가 없으면 빈 딕셔너리로 생성
# 2단계 키: enabled_labs_experiments
# enabled_labs_experiments항목에 unsafely-treat-insecure-origikey_as_securen-as-secure가 등록되어 있어야 함
if key_enable_labs not in data[key_browser]:
data[key_browser][key_enable_labs] = [] # 키가 없으면 빈 리스트로 생성
labs_list = data[key_browser].get(key_enable_labs, [])
if key_as_secure not in labs_list:
labs_list.append(key_as_secure)
data[key_browser][key_enable_labs] = labs_list
# 2단계 키: enabled_labs_experiments_origin_lists
if key_origin_lists not in data[key_browser]:
data[key_browser][key_origin_lists] = {} # 키가 없으면 빈 딕셔너리로 생성
# 3단계 키: unsafely-treat-insecure-origin-as-secure
# MES 접속URL 등록
data[key_browser][key_origin_lists][key_as_secure] = new_url
# Local State 파일은 구조가 매우 길기 때문에, 파일 크기가 변경되면 안 됩니다.
# 기존 파일을 덮어쓰기 위해 'w' 모드를 사용합니다.
with open(file_path, 'w', encoding='utf-8') as f:
# indent=None, separators=(',', ':') : 원본 Local State 파일은 가독성을 위한
# 들여쓰기 없이 한 줄로 저장되는 경우가 많으므로, 이를 유지하는 것이 안전합니다.
json.dump(data, f, indent=None, separators=(',', ':'))
# print(f"{browser_name}에서 읽은 'unsafely-treat-insecure-origin-as-secure' 값:")
# print(f"Old URL - {old_url}")
# print(f"New URL - {new_url}")
return True
except json.JSONDecodeError:
print(f"❌ 에러: {browser_name} Local State 파일의 JSON 형식이 올바르지 않습니다.")
return False
except Exception as e:
print(f"❌ 예상치 못한 오류 발생: {e}")
return False
def time_to_chromium_format(gubun: str):
"""
현재 UTC 시간을 Chromium/Chrome이 사용하는 시간 형식(1601년 1월 1일
UTC 자정부터 경과한 마이크로초)으로 변환하여 반환합니다.
"""
# 1. 1601년 1월 1일 UTC를 기준으로 하는 datetime 객체 정의
CHROMIUM_EPOCH = datetime.datetime(1601, 1, 1, tzinfo=datetime.timezone.utc)
# 2. 현재 UTC 시간
# time.time()은 1970년 1월 1일 UTC부터의 초를 반환합니다.
# datetime.datetime.now(datetime.timezone.utc)를 사용해도 되지만,
# time.time()을 사용하면 부동 소수점 오차를 최소화할 수 있습니다.
if gubun == 'added':
utc_time = datetime.datetime.fromtimestamp(time.time(), tz=datetime.timezone.utc)
elif gubun == 'expired':
utc_time = datetime.datetime(2099, 12, 31, 23, 59, 59, tzinfo=datetime.timezone.utc)
else:
utc_time = datetime.datetime(2025, 11, 16, 23, 59, 59, tzinfo=datetime.timezone.utc)
# 3. 1601-01-01 UTC 와 현재 UTC 시간의 차이 계산
time_difference = utc_time - CHROMIUM_EPOCH
# 4. 차이를 총 마이크로초로 변환 (time.timedelta.total_seconds()를 사용)
# total_seconds()는 소수점 이하까지 정확한 초를 반환합니다.
total_microseconds = int(time_difference.total_seconds() * 1_000_000)
return str(total_microseconds)
def register_ie_mode_page(new_url: str):
"""
Internet Explorer 모드 페이지 등록(설정 > 기본 브라우저 > Internet Explorer 호환성)
"""
if not terminate_browser("edge"):
return False
# 1. 파일 경로 설정
appdata_local_path = Path(os.getenv('LOCALAPPDATA'))
file_path = appdata_local_path / "Microsoft" / "Edge" / "User Data" / "Default" / "Preferences"
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
key_level1 = "dual_engine"
key_level2 = "user_list_data_1"
key_level3_urls = new_url.split(",")
ie_mode_pages = data.get(key_level1, {}) \
.get(key_level2, {})
for temp in key_level3_urls:
key_level3 = temp.strip()
if key_level3 not in ie_mode_pages:
data[key_level1][key_level2][key_level3] = {}
else:
data[key_level1][key_level2][key_level3].clear()
data[key_level1][key_level2][key_level3]["date_added"] = time_to_chromium_format('added')
data[key_level1][key_level2][key_level3]["engine"] = 2
data[key_level1][key_level2][key_level3]["source"] = 3
data[key_level1][key_level2][key_level3]["visit_state"] = False
data[key_level1][key_level2][key_level3]["visits_after_expiration"] = 0
# data[key_level1][key_level2][key_level3]["expiration_date"] = time_to_chromium_format('expired')
# data[key_level1][key_level2][key_level3]["date_expired"] = time_to_chromium_format('expired')
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=None, separators=(',', ':'))
# print(f"현재 등록된 IE 모드 페이지: {data.get(key_level1, {}).get(key_level2, {}).keys()}")
return True
except json.JSONDecodeError:
print(f"❌ 에러: Preferences 파일의 JSON 형식이 올바르지 않습니다.")
return False
except Exception as e:
print(f"❌ 예상치 못한 오류 발생: {e}")
return False
def confirm_continuation_in_cmd():
# CMD 프롬프트에서 사용자에게 'Y/N' 입력을 받아 계속 진행 여부를 확인합니다.
# 1. 경고 메시지 출력
print("\n" + "*"*50)
print(" Registering for Secure URLs and IE Mode Pages")
print(" (Created by KVM IT on 2025.12.18)")
print("*"*50)
print(" ⚠️ 경고: 작업 확인⚠️")
print("계속 진행하면 모든 브라우저 세션이 강제로 닫힙니다.")
# 2. 사용자 입력 루프
while True:
# 사용자로부터 입력 받기
# .strip().lower()를 사용하여 입력의 앞뒤 공백을 제거하고 소문자로 변환
response = input("계속 진행하시겠습니까? (Y/N)(Yes/No)(예/아니오): ").strip().lower()
# '예'를 선택한 경우
if response in ['y', 'yes', '예']:
print("\n✔️ 사용자 확인: 작업을 계속 진행합니다.")
# 여기에 실제 브라우저를 닫고 진행할 코드를 추가합니다.
break # while 루프를 빠져나가 함수를 종료 (진행)
# '아니오'를 선택한 경우
elif response in ['n', 'no', '아니오']:
print("\n❌ 사용자 취소: 작업을 종료합니다. (브라우저를 닫지 않습니다.)")
sys.exit(0) # 프로그램 강제 종료
# 유효하지 않은 입력인 경우
else:
print("→ 잘못된 입력입니다. 'Y/Yes/예' 또는 'N/No/아니오'을 입력해 주세요.")
if __name__ == "__main__":
confirm_continuation_in_cmd()
new_url = 'http://58.54.160.110:1134/,http://58.54.160.110:1136/,http://58.54.160.110:1137/,http://58.54.160.110:1152/,'
new_url += 'http://58.54.160.111:1134/,http://58.54.160.111:1136/,http://58.54.160.111:1137/,http://58.54.160.111:1152/'
# 1. Chrome 파일에서 값 읽기 시도
print("\n--------------------------\n")
if register_secure_url('chrome', new_url):
print(f"Chrome 브라우저의 Secure URLs 등록 작업이 성공하였습니다.")
# 2. Edge 파일에서 값 읽기 시도
print("\n--------------------------\n")
if register_secure_url('edge', new_url):
print(f"Edge 브라우저의 Secure URLs 등록 작업이 성공하였습니다.")
print("\n--------------------------\n")
# 3. Edge에 IE 모드 페이지 등록
if register_ie_mode_page('http://58.54.160.110:1134/'):
print(f"Edge 브라우저에서 IE Mode Pages 등록 작업이 성공하였습니다.")
