<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Categories on Proofs Bond</title>
    <link>https://proofs.bond/categories/</link>
    <description>Recent content in Categories on Proofs Bond</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    
	<atom:link href="https://proofs.bond/categories/index.xml" rel="self" type="application/rss+xml" />
    
    
    
    <item>
      <title>深度学习之危险脚本识别</title>
      <link>https://proofs.bond/posts/deep-learning-for-secure-scripts/</link>
      <pubDate>Fri, 17 Oct 2025 00:23:27 +0800</pubDate>
      
      <guid>https://proofs.bond/posts/deep-learning-for-secure-scripts/</guid>
      <description>&lt;h1 id=&#34;总结没什么用-你弄几千个webshell一句话木马各种变种脚本看似很多很多但是在深度学习中几千个甚至是几万个样本完全沧海一粟跑完epoch全部是过拟合的结果&#34;&gt;总结:没什么用!!! 你弄几千个webshell,一句话木马各种变种脚本看似很多很多但是在深度学习中几千个甚至是几万个样本完全沧海一粟跑完epoch全部是过拟合的结果&lt;/h1&gt;
&lt;h2 id=&#34;但是学习还是可以的&#34;&gt;但是学习还是可以的!!!&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import torch
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from torch.optim import AdamW

class VulnerabilityDataset(Dataset):
    def __init__(self, data_list, tokenizer, max_length=512):
        self.data = data_list
        self.tokenizer = tokenizer
        self.max_length = max_length
        self.sensitive_keywords = {&amp;#34;exec&amp;#34;, &amp;#34;system&amp;#34;, &amp;#34;eval&amp;#34;, &amp;#34;os&amp;#34;, &amp;#34;subprocess&amp;#34;}

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        item = self.data[idx]
        code = str(item[&amp;#39;code&amp;#39;])
        label = int(item[&amp;#39;label&amp;#39;])

        encoding = self.tokenizer(
            code,
            add_special_tokens=True,
            max_length=self.max_length,
            padding=&amp;#39;max_length&amp;#39;,
            truncation=True,
            return_tensors=&amp;#39;pt&amp;#39;
        )

        input_ids = encoding[&amp;#39;input_ids&amp;#39;].squeeze()
        focus_mask = torch.zeros_like(input_ids, dtype=torch.float)   
        tokens = self.tokenizer.convert_ids_to_tokens(input_ids)

        for i, token in enumerate(tokens):
            clean_token = token.replace(&amp;#39;Ġ&amp;#39;, &amp;#39;&amp;#39;)
            if clean_token in self.sensitive_keywords:
                focus_mask[i] = 1.0

        return {
            &amp;#39;input_ids&amp;#39;: encoding[&amp;#39;input_ids&amp;#39;].squeeze(), 
            &amp;#39;attention_mask&amp;#39;: encoding[&amp;#39;attention_mask&amp;#39;].squeeze(),
            &amp;#39;labels&amp;#39;: torch.tensor(label, dtype=torch.long),
            &amp;#39;focus_mask&amp;#39;: focus_mask
        }

device = torch.device(&amp;#34;cuda&amp;#34; if torch.cuda.is_available() else &amp;#34;cpu&amp;#34;)
print(f&amp;#34;Using device: {device}&amp;#34;)

raw_data = [
    {&amp;#34;code&amp;#34;: &amp;#34;def safe_func(): print(&amp;#39;hello&amp;#39;)&amp;#34;, &amp;#34;label&amp;#34;: 0},
    {&amp;#34;code&amp;#34;: &amp;#34;def vuln_func(): exec(user_input)&amp;#34;, &amp;#34;label&amp;#34;: 1},
    {&amp;#34;code&amp;#34;: &amp;#34;x = 1 + 1&amp;#34;, &amp;#34;label&amp;#34;: 0},
    {&amp;#34;code&amp;#34;: &amp;#34;import os; os.system(&amp;#39;rm -rf /&amp;#39;)&amp;#34;, &amp;#34;label&amp;#34;: 1} # 增加一个样本以适应 batch_size=2
]

model_name = &amp;#34;microsoft/graphcodebert-base&amp;#34;
tokenizer = AutoTokenizer.from_pretrained(model_name)
dataset = VulnerabilityDataset(raw_data, tokenizer)
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)

model = AutoModelForSequenceClassification.from_pretrained(
    model_name, 
    num_labels=2, 
    output_attentions=True,
    use_safetensors=True,
    attn_implementation=&amp;#34;eager&amp;#34;
)

model.to(device)
optimizer = AdamW(model.parameters(), lr=2e-5)
model.train()
mse_loss_fn = torch.nn.MSELoss()

print(&amp;#34;\n--- 开始训练 ---&amp;#34;)
for epoch in range(3):
    total_loss = 0
    for batch in dataloader:
        optimizer.zero_grad()

        input_ids = batch[&amp;#39;input_ids&amp;#39;].to(device)
        attention_mask = batch[&amp;#39;attention_mask&amp;#39;].to(device)
        labels = batch[&amp;#39;labels&amp;#39;].to(device)
        
        target_focus = batch[&amp;#39;focus_mask&amp;#39;].to(device) 
        
        outputs = model(
            input_ids=input_ids, 
            attention_mask=attention_mask, 
            labels=labels
        )
        
        cls_loss = outputs.loss
        last_layer_attn = outputs.attentions[-1] 
        cls_attention = last_layer_attn[:, :, 0, :]
        avg_cls_attention = torch.mean(cls_attention, dim=1)
        attn_loss = mse_loss_fn(avg_cls_attention, target_focus) 
        lambda_factor = 10.0
        loss = cls_loss + (lambda_factor * attn_loss)
        total_loss += loss.item()    
        loss.backward()
        optimizer.step()
        
        print(f&amp;#34;Epoch {epoch+1} | Total Loss: {loss.item():.4f} (Cls: {cls_loss.item():.4f}, Attn: {attn_loss.item():.4f})&amp;#34;)
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    
    
    
    <item>
      <title>使用虚拟货币数据进行深度学习</title>
      <link>https://proofs.bond/posts/deep-learningof-virtual-currency/</link>
      <pubDate>Fri, 27 Jun 2025 00:23:27 +0800</pubDate>
      
      <guid>https://proofs.bond/posts/deep-learningof-virtual-currency/</guid>
      <description>&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import argparse
import json
import math
import os
from typing import List, Optional, Tuple

import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import joblib

DEVICE = torch.device(&amp;#34;cuda&amp;#34; if torch.cuda.is_available() else &amp;#34;cpu&amp;#34;)

DEFAULT_WINDOW = 360
DEFAULT_HORIZON = 120
DEFAULT_SCALE_Y = 10.0

BATCH_SIZE = 256

EPS = 1e-8

_signal_cached = {
    &amp;#34;model&amp;#34;: None,
    &amp;#34;scaler&amp;#34;: None,
    &amp;#34;y_mean&amp;#34;: 0.0,
    &amp;#34;y_std&amp;#34;: 1.0,
    &amp;#34;scale_y&amp;#34;: DEFAULT_SCALE_Y,
    &amp;#34;window&amp;#34;: DEFAULT_WINDOW,
    &amp;#34;horizon&amp;#34;: DEFAULT_HORIZON,
}

def load_artifacts_for_signal(model_path: str,
                              scaler_path: str,
                              label_stats_path: str,
                              input_size_hint: int = None,
                              hidden: int = 256,
                              layers: int = 2,
                              bidirectional: bool = True,
                              pooling: str = &amp;#34;attn&amp;#34;):

    scaler = joblib.load(scaler_path)
    in_features = getattr(scaler, &amp;#34;n_features_in_&amp;#34;, None)
    if in_features is None and hasattr(scaler, &amp;#34;mean_&amp;#34;):
        in_features = int(getattr(scaler, &amp;#34;mean_&amp;#34;).shape[0])
    if input_size_hint is not None:
        in_features = int(input_size_hint)
    if not in_features:
        raise ValueError(&amp;#34;无法推断输入特征数，请传 input_size_hint&amp;#34;)
    with open(label_stats_path, &amp;#34;r&amp;#34;) as f:
        stats = json.load(f)
    y_mean = float(stats.get(&amp;#34;y_mean&amp;#34;, 0.0))
    y_std  = float(stats.get(&amp;#34;y_std&amp;#34;, 1.0))
    scale_y = float(stats.get(&amp;#34;scale&amp;#34;, DEFAULT_SCALE_Y))

    # 构建模型（按训练时结构）
    model = GRURegressor(
        input_size=in_features,
        hidden_size=hidden,
        num_layers=layers,
        bidirectional=bidirectional,
        dropout=0.2,
        pooling=pooling,
    ).to(DEVICE)

    # 兼容纯 state_dict
    state = torch.load(model_path, map_location=DEVICE, weights_only=True)
    if isinstance(state, dict) and &amp;#34;state_dict&amp;#34; in state:
        state = state[&amp;#34;state_dict&amp;#34;]
    try:
        model.load_state_dict(state, strict=True)
    except Exception:
        # 若 input_size 不一致，可先用 strict=False 跑通；首次 get_generated_signal 会再次校验
        model.load_state_dict(state, strict=False)
    model.eval()

    _signal_cached.update(dict(
        model=model,
        scaler=scaler,
        y_mean=y_mean,
        y_std=y_std,
        scale_y=scale_y,
    ))


def get_generated_signal(df_recent):

    assert _signal_cached[&amp;#34;model&amp;#34;] is not None, &amp;#34;请先调用 load_artifacts_for_signal() 加载模型等文件&amp;#34;
    model      = _signal_cached[&amp;#34;model&amp;#34;]
    scaler     = _signal_cached[&amp;#34;scaler&amp;#34;]
    y_mean     = _signal_cached[&amp;#34;y_mean&amp;#34;]
    y_std      = _signal_cached[&amp;#34;y_std&amp;#34;]
    scale_y    = _signal_cached[&amp;#34;scale_y&amp;#34;]
    window     = _signal_cached.get(&amp;#34;window&amp;#34;, DEFAULT_WINDOW)
    horizon    = _signal_cached.get(&amp;#34;horizon&amp;#34;, DEFAULT_HORIZON)

    # 使用你已有的预处理：构造特征并标准化
    feats = _prepare_for_scaler(df_recent.copy())  # -&amp;gt; np.float32 of shape [N, F]
    feats = scaler.transform(feats).astype(np.float32)
    if feats.shape[0] &amp;lt; window:
        # 数据不足，不给信号
        return 0.0

    # 取最后一个滑窗
    X = feats[-window:]                       # [T, F]
    X = np.expand_dims(X, axis=0)            # [1, T, F]
    X_t = torch.from_numpy(X).to(DEVICE)

    with torch.no_grad():
        yhat_std = model(X_t).detach().cpu().numpy().ravel()[0]
        yhat_raw = yhat_std * y_std + y_mean
        sum_log_return = (yhat_raw / float(scale_y)) * math.sqrt(float(horizon))
        expected_return = np.expm1(sum_log_return)

    return float(expected_return)

# -----------------------------
# Model (same as training/inference)
# -----------------------------
class AttnPool(nn.Module):
    def __init__(self, dim):
        super().__init__()
        self.w = nn.Linear(dim, 1, bias=False)
    def forward(self, h):
        a = self.w(h).squeeze(-1)
        a = torch.softmax(a, dim=1)
        return (h * a.unsqueeze(-1)).sum(dim=1)

class GRURegressor(nn.Module):
    def __init__(self, input_size: int, hidden_size: int = 128, num_layers: int = 1,
                 bidirectional: bool = False, dropout: float = 0.0, pooling: str = &amp;#34;attn&amp;#34;):
        super().__init__()
        self.bidirectional = bidirectional
        self.num_directions = 2 if bidirectional else 1
        self.hidden_size = hidden_size
        self.pooling = pooling

        self.gru = nn.GRU(
            input_size=input_size, hidden_size=hidden_size, num_layers=num_layers,
            batch_first=True, bidirectional=bidirectional,
            dropout=dropout if num_layers &amp;gt; 1 else 0.0,
        )
        self.out_drop = nn.Dropout(p=0.2)

        dim = hidden_size * self.num_directions
        self.reg_head = nn.Linear(dim, 1)

        if self.pooling == &amp;#34;attn&amp;#34;:
            self.attn_pool = AttnPool(dim)

    def forward(self, x):
        out, _ = self.gru(x)
        if self.pooling == &amp;#34;mean&amp;#34;:
            feat = out.mean(dim=1)
        elif self.pooling == &amp;#34;attn&amp;#34;:
            feat = self.attn_pool(out)
        else:
            feat = out[:, -1, :]
        feat = self.out_drop(feat)
        y_reg = self.reg_head(feat).squeeze(-1)
        return y_reg

def _read_raw(csv_path: str) -&amp;gt; pd.DataFrame:
    if not os.path.exists(csv_path):
        raise FileNotFoundError(f&amp;#34;CSV not found: {csv_path}&amp;#34;)
    return pd.read_csv(csv_path)


def _extract_time_col(df: pd.DataFrame) -&amp;gt; Optional[pd.Series]:
    time_col = None
    if &amp;#34;close_time&amp;#34; in df.columns:
        time_col = df[&amp;#34;close_time&amp;#34;]
    elif &amp;#34;open_time&amp;#34; in df.columns:
        time_col = df[&amp;#34;open_time&amp;#34;]

    if time_col is None:
        return None

    s = time_col.copy()
    try:
        if pd.api.types.is_numeric_dtype(s) and s.max() &amp;gt; 1e12:
            s = pd.to_datetime(s, unit=&amp;#34;ms&amp;#34;, utc=True).dt.tz_convert(&amp;#34;UTC&amp;#34;)
        else:
            s = pd.to_datetime(s, utc=True, errors=&amp;#34;coerce&amp;#34;)
            if s.isna().all() and pd.api.types.is_numeric_dtype(time_col):
                s = pd.to_datetime(time_col, unit=&amp;#34;s&amp;#34;, utc=True)
    except Exception:
        return None
    return s.dt.strftime(&amp;#34;%Y-%m-%dT%H:%M:%SZ&amp;#34;)


def _prepare_for_scaler(df: pd.DataFrame) -&amp;gt; pd.DataFrame:
    df = df.copy()

    for c in [&amp;#34;open_time&amp;#34;, &amp;#34;close_time&amp;#34;, &amp;#34;ignore&amp;#34;]:
        if c in df.columns:
            df = df.drop(columns=[c])

    for c in df.columns:
        df[c] = pd.to_numeric(df[c], errors=&amp;#34;coerce&amp;#34;)

    if &amp;#34;close&amp;#34; in df.columns:
        close = df[&amp;#34;close&amp;#34;].astype(float).values
    else:
        close = df.iloc[:, 0].astype(float).values
        df[&amp;#34;close&amp;#34;] = close
    lr = np.zeros_like(close, dtype=np.float64)
    lr[1:] = np.log((close[1:] + EPS) / (close[:-1] + EPS))
    df[&amp;#34;log_return&amp;#34;] = lr

    ema20 = df[&amp;#34;close&amp;#34;].ewm(span=20, adjust=False, min_periods=5).mean()
    ema60 = df[&amp;#34;close&amp;#34;].ewm(span=60, adjust=False, min_periods=10).mean()
    df[&amp;#34;ema_diff&amp;#34;] = (ema20 - ema60) / (ema60.abs() + EPS)

    vol_roll = df[&amp;#34;log_return&amp;#34;].rolling(60, min_periods=10).std()
    df[&amp;#34;vol_roll&amp;#34;] = vol_roll

    df = df.replace([np.inf, -np.inf], np.nan).dropna().reset_index(drop=True)

    keep_cols = [&amp;#34;vol_roll&amp;#34;, &amp;#34;ema_diff&amp;#34;, &amp;#34;volume&amp;#34;, &amp;#34;open&amp;#34;, &amp;#34;low&amp;#34;, &amp;#34;high&amp;#34;]
    for c in keep_cols:
        if c not in df.columns:
            raise KeyError(f&amp;#34;缺少必须特征列: {c}&amp;#34;)
    df = df[keep_cols].values.astype(np.float32)
    return df


def _windows_view(data: np.ndarray, window: int) -&amp;gt; np.ndarray:
    N = data.shape[0] - window + 1
    xs: List[np.ndarray] = []
    for i in range(N):
        xs.append(data[i:i+window])
    return np.stack(xs, axis=0)


def pred_to_metrics(yhat_std: np.ndarray, y_mean: float, y_std: float, scale_y: float) -&amp;gt; np.ndarray:
    yhat_raw = yhat_std * y_std + y_mean
    sum_log_return = (yhat_raw / float(scale_y)) * math.sqrt(float(DEFAULT_HORIZON))
    expected_return = np.expm1(sum_log_return)
    return expected_return

def main():
    ap = argparse.ArgumentParser(description=&amp;#34;Generate per-bar signals CSV for backtesting.&amp;#34;)
    ap.add_argument(&amp;#34;--csv&amp;#34;, type=str, required=True, help=&amp;#34;Input klines CSV.&amp;#34;)
    ap.add_argument(&amp;#34;--model&amp;#34;, type=str, default=&amp;#34;return/checkpoints/best_icp.pt&amp;#34;, help=&amp;#34;Trained model state_dict path.&amp;#34;)
    ap.add_argument(&amp;#34;--scaler&amp;#34;, type=str, default=&amp;#34;return/configs/scaler.joblib&amp;#34;, help=&amp;#34;StandardScaler path.&amp;#34;)
    ap.add_argument(&amp;#34;--label-stats&amp;#34;, type=str, default=&amp;#34;return/configs/label_stats.json&amp;#34;, help=&amp;#34;Label stats JSON path.&amp;#34;)

    ap.add_argument(&amp;#34;--hidden&amp;#34;, type=int, default=256)
    ap.add_argument(&amp;#34;--layers&amp;#34;, type=int, default=2)

    ap.add_argument(&amp;#34;--out&amp;#34;, type=str, default=&amp;#34;signals.csv&amp;#34;, help=&amp;#34;Output CSV path.&amp;#34;)

    args = ap.parse_args()

    # Load artifacts
    if not os.path.exists(args.scaler):
        raise FileNotFoundError(f&amp;#34;Scaler not found: {args.scaler}&amp;#34;)
    scaler = joblib.load(args.scaler)

    if not os.path.exists(args.label_stats):
        raise FileNotFoundError(f&amp;#34;Label stats not found: {args.label_stats}&amp;#34;)
    with open(args.label_stats, &amp;#34;r&amp;#34;) as f:
        label_stats = json.load(f)
    y_mean = float(label_stats.get(&amp;#34;y_mean&amp;#34;, 0.0))
    y_std  = float(label_stats.get(&amp;#34;y_std&amp;#34;, 1.0))
    scale_y = float(label_stats.get(&amp;#34;scale&amp;#34;, DEFAULT_SCALE_Y))

    # Load data
    raw = _read_raw(args.csv)
    time_series = _extract_time_col(raw)  # may be None
    df = _prepare_for_scaler(raw)
    data = df.astype(np.float32)
    data = scaler.transform(data).astype(np.float32)

    # windows
    T = DEFAULT_WINDOW
    N_total = data.shape[0]
    if N_total &amp;lt; T:
        raise ValueError(f&amp;#34;Not enough rows: need at least {T}, got {N_total}&amp;#34;)

    # We&amp;#39;ll predict for window ending at each bar t in [T-1 .. N_total-1]
    # And sub-sample by step for speed.
    idx_ends = np.arange(T-1, N_total, 1, dtype=np.int64)  # bar index of window end
    # Build batched tensor for inference
    results = []

    # Build model
    input_size = data.shape[1]
    model = GRURegressor(
        input_size=input_size,
        hidden_size=args.hidden,
        num_layers=args.layers,
        bidirectional=True,
        dropout=0.2,
        pooling=&amp;#34;attn&amp;#34;,
    ).to(DEVICE)

    # Safe weights-only load (PyTorch &amp;gt;= 2.5; retains compatibility with state_dict checkpoints)
    state = torch.load(args.model, map_location=DEVICE, weights_only=True)
    model.load_state_dict(state, strict=True)
    model.eval()

    batch = BATCH_SIZE
    with torch.no_grad():
        # Build windows on the fly to avoid huge memory on very long series
        for start in range(0, len(idx_ends), batch):
            ends_batch = idx_ends[start:start+batch]
            X = np.stack([data[e-T+1:e+1] for e in ends_batch], axis=0)  # [B, T, F]
            X_t = torch.from_numpy(X).to(DEVICE)
            yhat_std = model(X_t).detach().cpu().numpy().astype(np.float64)  # [B]

            expected_return = pred_to_metrics(
                yhat_std, y_mean, y_std, DEFAULT_SCALE_Y
            )

            # Collect rows
            for j, e in enumerate(ends_batch):
                idx = int(e)
                ts = &amp;#34;&amp;#34;  # default empty
                if time_series is not None and idx &amp;lt; len(time_series):
                    ts = str(time_series.iloc[idx])
                results.append({
                    &amp;#34;index&amp;#34;: idx,
                    &amp;#34;time&amp;#34;: ts,
                    &amp;#34;expected_return&amp;#34;: float(expected_return[j]),
                })

    # Save to CSV
    out_dir = os.path.dirname(args.out)
    if out_dir:
        os.makedirs(out_dir, exist_ok=True)
    pd.DataFrame(results).to_csv(args.out, index=False, encoding=&amp;#34;utf-8&amp;#34;)
    print(f&amp;#34;Wrote {len(results)} rows to {args.out}&amp;#34;)


if __name__ == &amp;#34;__main__&amp;#34;:
    main()
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;虚拟货币价格预测&#34;&gt;&lt;strong&gt;虚拟货币价格预测&lt;/strong&gt;&lt;/h1&gt;
&lt;h1 id=&#34;回测结果3-6月表现不错拉长到一年结果就完蛋但是grok评价是核弹级别的结果直接可以在金融市场抢钱&#34;&gt;回测结果3-6月表现不错,拉长到一年结果就完蛋,但是grok评价是核弹级别的结果直接可以在金融市场抢钱&lt;/h1&gt;
&lt;h1 id=&#34;ai不会说的或者不懂金融的不知道的因为几个月区间货币价格涨幅不大导致误差很小模型一直在收敛以为学到东西了其实什么也没学到&#34;&gt;AI不会说的或者不懂金融的不知道的因为几个月区间货币价格涨幅不大导致误差很小模型一直在收敛以为学到东西了其实什么也没学到&lt;/h1&gt;
&lt;h1 id=&#34;总结我支持金融市场完全随机假说&#34;&gt;总结:我支持金融市场完全随机假说！&lt;/h1&gt;
</description>
    </item>
    
    
    
    <item>
      <title>某SRC的web缓存问题</title>
      <link>https://proofs.bond/posts/web_caching_issues/</link>
      <pubDate>Thu, 27 Mar 2025 00:23:27 +0800</pubDate>
      
      <guid>https://proofs.bond/posts/web_caching_issues/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://example.com/user/profile&#34;&gt;https://example.com/user/profile&lt;/a&gt; 访问后端服务器执行查看用户信息逻辑代码
&lt;a href=&#34;https://example.com/user/profile;1.jpg&#34;&gt;https://example.com/user/profile;1.jpg&lt;/a&gt; 处理缓存的逻辑代码会把这个以为是图片缓存起来而后端服务器依然认为这是在查询用户信息的后端逻辑，所以返回了用户信息
&lt;a href=&#34;https://example.com/user/profile;1.jpg&#34;&gt;https://example.com/user/profile;1.jpg&lt;/a&gt; 再次访问会优先从缓存信息中获取，而不会再次执行查看用户信息的逻辑代码。这样就导致了缓存问题。&lt;/p&gt;
&lt;p&gt;这个SRC中我发现了包含了用户的登陆Token&lt;/p&gt;
</description>
    </item>
    
    
    
    <item>
      <title>我在移动端常用的安全检测方式</title>
      <link>https://proofs.bond/posts/security-detection-methods-i-commonly-use-on-mobile-devices/</link>
      <pubDate>Thu, 28 Oct 2021 00:23:27 +0800</pubDate>
      
      <guid>https://proofs.bond/posts/security-detection-methods-i-commonly-use-on-mobile-devices/</guid>
      <description>&lt;p&gt;1.IOS端&lt;/p&gt;
&lt;p&gt;IOS系统下的APP不能反编译(能反编译一些无用的包含头文件的代码),就只能用抓包工具进行检测&lt;/p&gt;
&lt;p&gt;这部分设置好代理(Burp,Charles)以后与常规的Web安全检测没什么区别不做过多介绍&lt;/p&gt;
&lt;p&gt;2.Android&lt;/p&gt;
&lt;p&gt;1.抓包(Web安全检测)&lt;/p&gt;
&lt;p&gt;2.反编译&lt;/p&gt;
&lt;p&gt;APK TOOL：这是谷歌提供的的编译工具，我们知道APK其实就是一个压缩文件，我们完全可以把.apk文件后缀改成.zip，这样我们就可以获取里面的资源文件（图片，res目录下的xml文件）和AndroidManifest.xml（这个是乱码的）如果你使用 apk tool 来进行反编译 apk 就不会出现这种问题了&lt;/p&gt;
&lt;p&gt;AndroidManifest.xml包含了Android相关开发的所需的配置项,有些配置项默认是打开并且不安全的,具体相关内容可以查询Google的开发文档&lt;/p&gt;
&lt;p&gt;dex2jar：将apk反编译成java源码（classes.dex转化成jar文件）&lt;/p&gt;
&lt;p&gt;jd-gui:用来查看 jar 包里面的代码的一种工具。&lt;/p&gt;
&lt;p&gt;上面两款工具基本上会逆向App的都用过。能反编译部分的出来apk代码。这就跟一般的代码审计一样需要看代码的业务功能来找,我特别喜欢来找一些敏感信息泄露。一些App与后端的加密方式或者Key之类的会放在App的代码中,这部分能被反编译出来&lt;/p&gt;
&lt;p&gt;Android调试桥(Adb)&lt;/p&gt;
&lt;p&gt;Android 调试桥 (adb) 是一种功能多样的命令行工具，可让您与设备进行通信。adb 命令可用于执行各种设备操作（例如安装和调试应用），并提供对 Unix shell（可用来在设备上运行各种命令）的访问权限。它是一种客户端-服务器程序，包括以下三个组件：&lt;/p&gt;
&lt;p&gt;他是一款调试工具,相当于App的shell&lt;/p&gt;
&lt;p&gt;Android 开发的四大组件分别是：活动（activity），用于表现功能；服务（service），后台运行服务，不提供界面呈现；广播接受者（Broadcast Receive），勇于接收广播；内容提供者（Content Provider）&lt;/p&gt;
&lt;p&gt;Android四大组件是能直接通过ADB启动的&lt;/p&gt;
&lt;p&gt;举一个例子.我们有一个Activity是验证,类似 VerifyActivity验证完进入MainActivity 但在ADB下你可以直接使用ADB启动MainActivity从而跳过VerifyActivity造成一个跳过验证的安全问题&lt;/p&gt;
&lt;p&gt;以上是我大概是移动端会用到的安全检测&lt;/p&gt;
&lt;p&gt;上面每一个检测都可以单独写一篇篇幅不小的文章，这里简要描述一下&lt;/p&gt;
</description>
    </item>
    
    
    
    <item>
      <title>在LeetCode上面的一道算法题</title>
      <link>https://proofs.bond/posts/an-algorithm-problem-on-leetcode/</link>
      <pubDate>Wed, 27 Oct 2021 00:23:27 +0800</pubDate>
      
      <guid>https://proofs.bond/posts/an-algorithm-problem-on-leetcode/</guid>
      <description>&lt;h1 id=&#34;两数之和&#34;&gt;&lt;strong&gt;两数之和&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://leetcode-cn.com/problems/two-sum/&#34;&gt;查看详情&lt;/a&gt;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;class Solution {

    /**
     * @param Integer[] $nums
     * @param Integer $target
     * @return Integer[]
     */
function twoSum($nums, $target) {
    $i = 0;
    while($i &amp;lt; count($nums))
    {
        for($j = ($i+1); $j &amp;lt; count($nums); $j++){
            if(($nums[$i]+$nums[$j]) == $target){
                return array($i, $j);
            }
        }
        $i++;
    }
}
}
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    
    
    
    <item>
      <title>OWASP Top10 2021 (2.Cryptographic Failures失败的加密方式)</title>
      <link>https://proofs.bond/posts/cryptographic-failures/</link>
      <pubDate>Thu, 23 Sep 2021 00:23:27 +0800</pubDate>
      
      <guid>https://proofs.bond/posts/cryptographic-failures/</guid>
      <description>&lt;p&gt;OWASP Top10 2021排第二的Cryptographic Failures(失败的加密方式)
原谅我初级的翻译
与上一篇不同是Broken Access Control影响业务和影响数据的区别
既然是加密肯定是涉及到敏感数据例如密码,身份证,银行卡号等等
在加密过程中或者直接为加密就造成了Cryptographic Failures(失败的加密方式)
举例说明(代码)
index.html&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;#34;en&amp;#34;&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&amp;#34;UTF-8&amp;#34;&amp;gt;
&amp;lt;meta http-equiv=&amp;#34;X-UA-Compatible&amp;#34; content=&amp;#34;IE=edge&amp;#34;&amp;gt;
&amp;lt;meta name=&amp;#34;viewport&amp;#34; content=&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&amp;gt;
&amp;lt;title&amp;gt;Cryptographic Failures&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;form action=&amp;#34;./login.php&amp;#34; method=&amp;#34;POST&amp;#34;&amp;gt;
&amp;lt;label for=&amp;#34;&amp;#34;&amp;gt;账号:&amp;lt;/label&amp;gt;
&amp;lt;input type=&amp;#34;text&amp;#34; name=&amp;#34;username&amp;#34;&amp;gt;
&amp;lt;label for=&amp;#34;&amp;#34;&amp;gt;密码:&amp;lt;/label&amp;gt;
&amp;lt;input type=&amp;#34;password&amp;#34; name=&amp;#34;password&amp;#34; id=&amp;#34;password&amp;#34;&amp;gt;
&amp;lt;button type=&amp;#34;submit&amp;#34;&amp;gt;提交&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;提交账号密码简单登陆页
第一没有使用HTTP证书导致造成了一个Cryptographic Failures(失败的加密方式)
提交
敏感数据没有加密(密码)造成了又一个Cryptographic Failures(失败的加密方式)
如果我们加密呢？
登陆
看代码知道使用了MD5加密
但大家知道MD5被碰撞也就是解密出来的几率很高所以现在被认为成了不安全的加密方式
使用不安全的加密方式又造成了又一个Cryptographic Failures(失败的加密方式)&lt;/p&gt;
&lt;p&gt;从上面几个例子可以得出Cryptographic Failures大致的一个分类，但不完全。Cryptographic Failures包含了很多内容
可以到密码学范畴例如王小云院士研究的密码学
也可以是要求密码大于12位包含大小写加特殊符号等等造成的问题都可以归纳为Cryptographic Failures&lt;/p&gt;
&lt;p&gt;修复：找合适的加密方式(非对称不可逆等等)&lt;/p&gt;
</description>
    </item>
    
    
    
    <item>
      <title>OWASP Top 10 2021(1.Broken Access Control未授权的访问控制)</title>
      <link>https://proofs.bond/posts/broken-access-contro/</link>
      <pubDate>Wed, 22 Sep 2021 00:23:27 +0800</pubDate>
      
      <guid>https://proofs.bond/posts/broken-access-contro/</guid>
      <description>&lt;p&gt;上图为OWASP Top 10 2021&lt;/p&gt;
&lt;p&gt;OWASP更新了来自2021的漏洞榜单&lt;/p&gt;
&lt;p&gt;Top1从Injection(注入)变成了Broken Access Control(未授权的访问控制)&lt;/p&gt;
&lt;p&gt;接下来展开说说Broken Access Control&lt;/p&gt;
&lt;p&gt;Broken Access Control我把它翻译成未授权的访问控制或者你直接理解成未授权访问也行&lt;/p&gt;
&lt;p&gt;大量的Bug Hunter报告发现了此类漏洞很自然的它上升至了Top1&lt;/p&gt;
&lt;p&gt;什么是未授权访问控制？&lt;/p&gt;
&lt;p&gt;访问控制强制执行策略，使用户不能在其预期权限之外采取行动。故障通常会导致未经授权的信息泄露、修改或破坏所有数据，或在用户范围之外执行业务功能。常见的访问控制漏洞包括：&lt;/p&gt;
&lt;p&gt;通过修改 URL、内部应用程序状态或 HTML 页面，或仅使用自定义 API 攻击工具来绕过访问控制检查&lt;/p&gt;
&lt;p&gt;允许将主键更改为他人的用户记录，允许查看或编辑他人的帐户。&lt;/p&gt;
&lt;p&gt;特权提升。以用户身份而不登录，或以用户身份登录时充当管理员。&lt;/p&gt;
&lt;p&gt;元数据操作，例如重放或篡改 JSON Web 令牌 (JWT) 访问控制令牌或 cookie 或被操纵以提升权限的隐藏字段，或滥用 JWT 失效&lt;/p&gt;
&lt;p&gt;CORS 错误配置允许未经授权的 API 访问。&lt;/p&gt;
&lt;p&gt;强制以未经身份验证的用户身份浏览经过身份验证的页面或以标准用户身份浏览特权页面。访问 API 时缺少对 POST、PUT 和 DELETE 的访问控制。&lt;/p&gt;
&lt;p&gt;用本不属于你的权限来做其他事为逻辑漏洞的一种这儿进行了细分&lt;/p&gt;
&lt;p&gt;用代码举一个简单的例子&lt;/p&gt;
&lt;p&gt;这里的内容不适合小白需要有一定的开发知识
开发中有一种情况我们需要展示用户的一些敏感数据，基于常规楼机我们会选择用户的唯一标识
也就是用户的id来获取用户的相关信息
如果当前登陆ID用户只能访问为自己ID的相关信息&lt;/p&gt;
&lt;p&gt;但是如果用户恶意修改来自GET参数ID的数值又没进行相关的访问控制这时便会造成一个未授权的访问控制&lt;/p&gt;
&lt;p&gt;原本属于admin uid为1的用户信息被test uid为2的用户读取到，造成信息泄露
上面我只举例了一种可能出现在代码逻辑当中的未授权的访问控制，能造成为授权访问控制漏洞点的方向很多。篇幅关系不一一举例用一例较为流行常见和易懂的例子来进行简单讲解
后面我会把owasp top都进行一个讲解。最后用一个靶场实现漏洞的全部复盘。敬请期待&lt;/p&gt;
&lt;p&gt;关于漏洞修复。未授权的访问控制修复无他。验证相关权限
参考目前较为流行的验证方式 JWT(Json web token)核心非对称加密算法&lt;/p&gt;
</description>
    </item>
    
    
    
    <item>
      <title>php代码来说明二次注入</title>
      <link>https://proofs.bond/posts/secondary-injection/</link>
      <pubDate>Thu, 27 Oct 2016 00:23:27 +0800</pubDate>
      
      <guid>https://proofs.bond/posts/secondary-injection/</guid>
      <description>&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;?php

$connect = mysql_connect()

$sql = &amp;#34;UPDATE users SET password=&amp;#39;$password&amp;#39; WHERE username=&amp;#39;$username&amp;#39;&amp;#34;;
// 传入参数username = 1111&amp;#39; 包含一个单引号
$connect.exec(Security($sql)); //过滤SQL注入 这个单引号被过滤存入数据
//取出username = 1111&amp;#39; 包含的单引号
$sql = &amp;#34;SELECT * FROM users WHERE username=&amp;#39;1111&amp;#39;&amp;#39; AND password=&amp;#39;$password&amp;#39;&amp;#34;; //这儿未过滤 造成二次注入
$connect.exec($sql); //忘记过滤导致二次注入

?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    
    
  </channel>
</rss>
