--
This commit is contained in:
@@ -56,6 +56,7 @@
|
|||||||
<button type="button" class="tls-tab" data-tab="vulnerabilities" role="tab" aria-selected="false">脆弱性</button>
|
<button type="button" class="tls-tab" data-tab="vulnerabilities" role="tab" aria-selected="false">脆弱性</button>
|
||||||
<button type="button" class="tls-tab" data-tab="compatibility" role="tab" aria-selected="false">互換性</button>
|
<button type="button" class="tls-tab" data-tab="compatibility" role="tab" aria-selected="false">互換性</button>
|
||||||
<button type="button" class="tls-tab" data-tab="log" role="tab" aria-selected="false">ログ</button>
|
<button type="button" class="tls-tab" data-tab="log" role="tab" aria-selected="false">ログ</button>
|
||||||
|
<button type="button" class="tls-tab" data-tab="history" role="tab" aria-selected="false">テスト履歴</button>
|
||||||
<button type="button" class="tls-tab" data-tab="json" role="tab" aria-selected="false">JSON</button>
|
<button type="button" class="tls-tab" data-tab="json" role="tab" aria-selected="false">JSON</button>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
@@ -399,6 +400,30 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{# -------- テスト履歴 -------- #}
|
||||||
|
<div class="tls-tab-panel" data-panel="history">
|
||||||
|
<section class="tls-section">
|
||||||
|
<h2 class="tls-section-title">過去のテスト結果 (同一対象)</h2>
|
||||||
|
{% if history %}
|
||||||
|
<table class="tls-table">
|
||||||
|
<thead><tr><th>実行日時</th><th>ランク</th><th>スコア</th><th>リンク</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
{% for h in history %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ h.finished_at_display or '—' }}</td>
|
||||||
|
<td>{{ h.rank or '—' }}</td>
|
||||||
|
<td>{{ "%.0f"|format(h.score or 0) }}</td>
|
||||||
|
<td><a href="/tools/tls-test/results/{{ h.id }}/" class="text-bright-green">{{ h.id[:8] }}…</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<div class="tls-log-row"><span class="tls-log-cat text-tx-alt">[info]</span><span class="tls-log-msg text-tx-alt">過去のテスト結果はありません</span></div>
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
{# -------- JSON -------- #}
|
{# -------- JSON -------- #}
|
||||||
<div class="tls-tab-panel" data-panel="json">
|
<div class="tls-tab-panel" data-panel="json">
|
||||||
<section class="tls-section">
|
<section class="tls-section">
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class TlsTestDB:
|
|||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS idx_tests_expires ON tests(expires_at);
|
CREATE INDEX IF NOT EXISTS idx_tests_expires ON tests(expires_at);
|
||||||
CREATE INDEX IF NOT EXISTS idx_tests_ip_created ON tests(client_ip, created_at);
|
CREATE INDEX IF NOT EXISTS idx_tests_ip_created ON tests(client_ip, created_at);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tests_target ON tests(target, created_at);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS test_progress (
|
CREATE TABLE IF NOT EXISTS test_progress (
|
||||||
test_id TEXT NOT NULL,
|
test_id TEXT NOT NULL,
|
||||||
@@ -185,6 +186,30 @@ class TlsTestDB:
|
|||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
def get_history_by_target(self, target: str, exclude_id: str | None = None, limit: int = 10) -> list[dict[str, Any]]:
|
||||||
|
conn = self._conn()
|
||||||
|
try:
|
||||||
|
cur = conn.cursor()
|
||||||
|
if exclude_id:
|
||||||
|
cur.execute(
|
||||||
|
"SELECT id, target, status, created_at, finished_at, rank, score, error_message"
|
||||||
|
" FROM tests WHERE target = ? AND id != ? AND status = 'done'"
|
||||||
|
" ORDER BY created_at DESC LIMIT ?",
|
||||||
|
(target, exclude_id, limit),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cur.execute(
|
||||||
|
"SELECT id, target, status, created_at, finished_at, rank, score, error_message"
|
||||||
|
" FROM tests WHERE target = ? AND status = 'done'"
|
||||||
|
" ORDER BY created_at DESC LIMIT ?",
|
||||||
|
(target, limit),
|
||||||
|
)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
cols = [c[0] for c in cur.description]
|
||||||
|
return [dict(zip(cols, r)) for r in rows]
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
def count_ip_in_window(self, client_ip: str, window_seconds: int) -> int:
|
def count_ip_in_window(self, client_ip: str, window_seconds: int) -> int:
|
||||||
cutoff = int(time.time()) - window_seconds
|
cutoff = int(time.time()) - window_seconds
|
||||||
conn = self._conn()
|
conn = self._conn()
|
||||||
|
|||||||
@@ -159,8 +159,12 @@ async def _gather(report: ReportProgress, finds: ReportFinding, result: ScanResu
|
|||||||
# SSL 2/3 → vulnerability findings; also record them as safety findings.
|
# SSL 2/3 → vulnerability findings; also record them as safety findings.
|
||||||
if sslv2_supported:
|
if sslv2_supported:
|
||||||
await emit(Finding("SSL/TLS Version", "SSL 2.0 supported", "SSLv2 は完全に破綻しています (DROWN)", "serious", 10, group=G_SAF))
|
await emit(Finding("SSL/TLS Version", "SSL 2.0 supported", "SSLv2 は完全に破綻しています (DROWN)", "serious", 10, group=G_SAF))
|
||||||
|
else:
|
||||||
|
await emit(Finding("SSL/TLS Version", "SSL 2.0 disabled", "", "good", 0, group=G_SAF))
|
||||||
if sslv3_supported:
|
if sslv3_supported:
|
||||||
await emit(Finding("SSL/TLS Version", "SSL 3.0 supported", "POODLE 攻撃が可能", "serious", 10, group=G_SAF))
|
await emit(Finding("SSL/TLS Version", "SSL 3.0 supported", "POODLE 攻撃が可能", "serious", 10, group=G_SAF))
|
||||||
|
else:
|
||||||
|
await emit(Finding("SSL/TLS Version", "SSL 3.0 disabled", "", "good", 0, group=G_SAF))
|
||||||
if version_support.get(C.TLS_1_0):
|
if version_support.get(C.TLS_1_0):
|
||||||
await emit(Finding("SSL/TLS Version", "TLS 1.0 supported", "RFC 8996 で廃止済み", "notgood", 4, group=G_SAF))
|
await emit(Finding("SSL/TLS Version", "TLS 1.0 supported", "RFC 8996 で廃止済み", "notgood", 4, group=G_SAF))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -80,6 +80,15 @@ def tls_results_context(job: dict, test_id: str, request: Request, tls_test_db)
|
|||||||
if step not in seen_steps:
|
if step not in seen_steps:
|
||||||
log_entries += [{"kind": "finding", "finding": f} for f in fs]
|
log_entries += [{"kind": "finding", "finding": f} for f in fs]
|
||||||
|
|
||||||
|
target = (result.get("target") or job.get("target") or "").strip()
|
||||||
|
history = tls_test_db.get_history_by_target(target, exclude_id=test_id, limit=10) if target else []
|
||||||
|
for h in history:
|
||||||
|
try:
|
||||||
|
ts = h.get("finished_at") or h.get("created_at") or 0
|
||||||
|
h["finished_at_display"] = datetime.datetime.fromtimestamp(int(ts)).strftime("%Y-%m-%dT%H:%M:%S") if ts else ""
|
||||||
|
except Exception:
|
||||||
|
h["finished_at_display"] = ""
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"test_id": test_id,
|
"test_id": test_id,
|
||||||
"job": job,
|
"job": job,
|
||||||
@@ -90,4 +99,5 @@ def tls_results_context(job: dict, test_id: str, request: Request, tls_test_db)
|
|||||||
"finished_at_display": finished_at_display,
|
"finished_at_display": finished_at_display,
|
||||||
"share_url": str(request.url).split("#", 1)[0],
|
"share_url": str(request.url).split("#", 1)[0],
|
||||||
"log_entries": log_entries,
|
"log_entries": log_entries,
|
||||||
|
"history": history,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user