728x90

<html>
<head>
<script>
/**
*
*  Secure Hash Algorithm (SHA256)
*  http://www.webtoolkit.info/
*
*  Original code by Angel Marin, Paul Johnston.
*
**/
 
function SHA256(s){
    var chrsz   = 8;
    var hexcase = 0;

    function safe_add (x, y) {
        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xFFFF);
    }

    function S (X, n) { return ( X >>> n ) | (X << (32 - n)); }
    function R (X, n) { return ( X >>> n ); }
    function Ch(x, y, z) { return ((x & y) ^ ((~x) & z)); }
    function Maj(x, y, z) { return ((x & y) ^ (x & z) ^ (y & z)); }
    function Sigma0256(x) { return (S(x, 2) ^ S(x, 13) ^ S(x, 22)); }
    function Sigma1256(x) { return (S(x, 6) ^ S(x, 11) ^ S(x, 25)); }
    function Gamma0256(x) { return (S(x, 7) ^ S(x, 18) ^ R(x, 3)); }
    function Gamma1256(x) { return (S(x, 17) ^ S(x, 19) ^ R(x, 10)); }

    function core_sha256 (m, l) {
        var K = new Array(0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0xFC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x6CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2);

        var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
        var W = new Array(64);
        var a, b, c, d, e, f, g, h, i, j;
        var T1, T2;

        m[l >> 5] |= 0x80 << (24 - l % 32);
        m[((l + 64 >> 9) << 4) + 15] = l;

        for ( var i = 0; i<m.length; i+=16 ) {
            a = HASH[0];
            b = HASH[1];
            c = HASH[2];
            d = HASH[3];
            e = HASH[4];
            f = HASH[5];
            g = HASH[6];
            h = HASH[7];

            for ( var j = 0; j<64; j++) {
                if (j < 16) W[j] = m[j + i];
                else W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
                T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
                T2 = safe_add(Sigma0256(a), Maj(a, b, c));

                h = g;
                g = f;
                f = e;
                e = safe_add(d, T1);
                d = c;
                c = b;
                b = a;
                a = safe_add(T1, T2);
            }

            HASH[0] = safe_add(a, HASH[0]);
            HASH[1] = safe_add(b, HASH[1]);
            HASH[2] = safe_add(c, HASH[2]);
            HASH[3] = safe_add(d, HASH[3]);
            HASH[4] = safe_add(e, HASH[4]);
            HASH[5] = safe_add(f, HASH[5]);
            HASH[6] = safe_add(g, HASH[6]);
            HASH[7] = safe_add(h, HASH[7]);
        }
        return HASH;
    }

    function str2binb (str) {
        var bin = Array();
        var mask = (1 << chrsz) - 1;
        for(var i = 0; i < str.length * chrsz; i += chrsz) {
            bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32);
        }
        return bin;
    }

    function Utf8Encode(string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    }

    function binb2hex (binarray) {
        var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
        var str = "";
        for(var i = 0; i < binarray.length * 4; i++) {
            str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
            hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF);
        }
        return str;
    }
    s = Utf8Encode(s);
    return binb2hex(core_sha256(str2binb(s), s.length * chrsz));
}
</script>
<body>
    <h3>Source : aabbccdd ==> <script>document.write(SHA256('aabbccdd'));</script></h3>
    <h3>Source : aa12ccdd ==> <script>document.write(SHA256('aa12ccdd'));</script></h3>
    <h3>Source : aa12한국dd ==> <script>document.write(SHA256('aa12한국dd'));</script></h3>
    <h3>Source : aa12한국%^# ==> <script>document.write(SHA256('aa12한국%^#'));</script></h3>
    <h3>Source : 1 ==> <script>document.write(SHA256('1'));</script></h3>
    <h3>Source : 2 ==> <script>document.write(SHA256('2'));</script></h3>
    <h3>Source : 3 ==> <script>document.write(SHA256('3'));</script></h3>
    <h3>Source : 4 ==> <script>document.write(SHA256('4'));</script></h3>
    <h3>Source : 5 ==> <script>document.write(SHA256('5'));</script></h3>
</body>

반응형
728x90

 

Python에서 데이터 시각화하는 다양한 방법

  • Python에서 데이터 시각화할 때 사용하는 다양한 라이브러리를 정리한 글입니다
  • 데이터 분석가들은 주로 Python(또는 R, SQL)을 가지고 데이터 분석을 합니다
    • R에는 ggplot이란 시각화에 좋은 라이브러리가 있는 반면 Python에는 어느 춘추전국시대처럼 다양한 라이브러리들이 있습니다
    • 각 라이브러리들마다 특징이 있기 때문에, 자유롭게 사용하면 좋을 것 같습니다
    • Zeppelin도 시각화할 때 사용할 수 있지만, 라이브러리는 아니기 때문에 이 문서에선 다루지 않습니다
    • 데이터 시각화 관련한 꿀팁은 카일 스쿨 2주차를 참고해주세요 :)
  • 저는 Jupyter Notebook으로 레포트를 작성해, 레포트의 보는 사람이 누구인지에 따라 다르게 그래프를 그렸습니다
    • 직접 그래프를 더 탐색해보고 싶은 목적이 있는 분들에게 보내는 그래프라면 동적인(Interactive) 그래프를 그렸습니다
    • 반복적인 레포트는 정적인 그래프 기반으로 작성한 후, 추가적인 내용이 궁금하면 대시보드로 가도록 유도했습니다
  • 이 문서는 맥북에서 작성되었으며, 부족한 내용이 있으면 연락주세요 :)
  • 현재 프론트단의 문제로 자바스크립트 기반 그래프는 처음엔 보이지 않을 수 있습니다. 10초 뒤 새로고침하면 나올거에요-!
  • plot.ly, pyecharts는 웹에서 정말 강력합니다. 꼭 직접 사용해보세요!
  • 라이브러리
    • matplotlib
    • seaborn
    • plotnine
    • folium
    • plot.ly
    • pyecharts

Matplotlib


  • Python에서 아마 가장 많이 쓰는 라이브러리입니다
  • pandas의 Dataframe을 바로 시각화할 때도 내부적으로 matplotlib을 사용합니다
  • 설치 pip3 install matplotlib
  • Matplotlib Tutorials
  • 데이터 사이언스 스쿨

import pandas as pd import numpy as np import matplotlib import matplotlib.pyplot as plt print("Matplotlib version", matplotlib.__version__) %matplotlib inline %config InlineBackend.figure_format = 'retina'

Matplotlib version 2.2.3

Figure의 구성 요소

  • 처음 matplotlib을 사용해 그래프를 그릴 때, 그래프와 관련된 명칭을 (영어 표현으로) 몰라 애를 먹었습니다
  • 여기 나온 표현을 숙지해두기만 해도 좋을 것 같습니다

Figure

  • Figure는 그림이 그려지는 도화지라고 생각할 수 있습니다
    • 우선 Figure를 그린 후, plt.subplots로 도화지를 분할해 각 부분에 그래프를 그리는 방식으로 진행합니다
    • plt.figure를 명시적으로 표현해주는 것이 좋으나, plot 함수에서 자동으로 figure를 생성하기 때문에 자주 사용하진 않습니다
    • 그러나 현재 figure에 접근해야 할 필요성이 있다면, plt.gcf()로 접근할 수 있습니다
  • size를 조절하고 싶은 경우엔 fig.set_size_inches(18.5, 10.5)
    • 또는 plt.figure(figsize=(10,5))
    • 또는 plt.rcParams['figure.figsize'] = (10,7)

Axes

  • Axes는 plot이 그려지는 공간입니다

Axis

  • plot의 축입니다

fig = plt.figure() fig.suptitle('figure sample plots') fig, ax_lst = plt.subplots(2, 2, figsize=(8,5)) ax_lst[0][0].plot([1,2,3,4], 'ro-') ax_lst[0][1].plot(np.random.randn(4, 10), np.random.randn(4,10), 'bo--') ax_lst[1][0].plot(np.linspace(0.0, 5.0), np.cos(2 * np.pi * np.linspace(0.0, 5.0))) ax_lst[1][1].plot([3,5], [3,5], 'bo:') ax_lst[1][1].plot([3,7], [5,4], 'kx') plt.show()

 

df = pd.DataFrame(np.random.randn(4,4))

df.plot(kind='barh')

Out[4]:

  • ggplot 스타일로 그리고 싶다면 아래 옵션 추가

plt.style.use('ggplot') pd.options.display.mpl_style = 'default'

fig = plt.figure() fig.suptitle('ggplot style') fig, ax_lst = plt.subplots(2, 2, figsize=(8,5)) ax_lst[0][0].plot([1,2,3,4], 'ro-') ax_lst[0][1].plot(np.random.randn(4, 10), np.random.randn(4,10), 'bo--') ax_lst[1][0].plot(np.linspace(0.0, 5.0), np.cos(2 * np.pi * np.linspace(0.0, 5.0))) ax_lst[1][1].plot([3,5], [3,5], 'bo:') ax_lst[1][1].plot([3,7], [5,4], 'kx') plt.show()

 

Seaborn


  • seaborn은 matplotlib을 기반으로 다양한 색 테마, 차트 기능을 추가한 라이브러리입니다
  • matplotlib에 의존성을 가지고 있습니다
  • matplotlib에 없는 그래프(히트맵, 카운트플랏 등)을 가지고 있습니다
  • 설치pip3 install seaborn
  • Seaborn Tutorials

import seaborn as sns print("Seaborn version : ", sns.__version__) sns.set() sns.set_style('whitegrid') sns.set_color_codes()

Seaborn version : 0.9.0

current_palette = sns.color_palette() sns.palplot(current_palette)

relplot

tips = sns.load_dataset("tips") sns.relplot(x="total_bill", y="tip", hue="smoker", style="smoker", data=tips)

Out[11]:

df = pd.DataFrame(dict(time=np.arange(500), value=np.random.randn(500).cumsum())) g = sns.relplot(x="time", y="value", kind="line", data=df) g.fig.autofmt_xdate()

Catplot

sns.catplot(x="day", y="total_bill", hue="smoker", col="time", aspect=.6, kind="swarm", data=tips)

Out[12]:

titanic = sns.load_dataset("titanic") g = sns.catplot(x="fare", y="survived", row="class", kind="box", orient="h", height=1.5, aspect=4, data=titanic.query("fare > 0")) g.set(xscale="log");

Pairplot

iris = sns.load_dataset("iris") sns.pairplot(iris)

Out[16]:

g = sns.PairGrid(iris) g.map_diag(sns.kdeplot) g.map_offdiag(sns.kdeplot, n_levels=6);

Heatmap

flights = sns.load_dataset("flights") flights = flights.pivot("month", "year", "passengers") plt.figure(figsize=(10, 10)) ax = sns.heatmap(flights, annot=True, fmt="d")

Plotnine


  • plotnine은 R의 ggplot2에 기반해 그래프를 그려주는 라이브러리입니다
  • R로 시각화하는 것이 익숙하신 분들에게 좋을 것 같습니다. 저는 사용해보진 않았습니다!
  • 공식 문서
  • 설치pip3 install plotnine

import plotnine from plotnine import * print("plontnine version :",plotnine.__version__)

plontnine version : 0.4.0

n = 10 df = pd.DataFrame({'x': np.arange(n), 'y': np.arange(n), 'yfit': np.arange(n) + np.tile([-.2, .2], n//2), 'cat': ['a', 'b']*(n//2)})

(ggplot(df) + geom_col(aes('x', 'y', fill='cat')) + geom_point(aes('x', y='yfit', color='cat')) + geom_path(aes('x', y='yfit', color='cat')) )

Out[39]:

df2 = pd.DataFrame({ 'letter': ['Alpha', 'Beta', 'Delta', 'Gamma'] * 2, 'pos': [1, 2, 3, 4] * 2, 'num_of_letters': [5, 4, 5, 5] * 2 }) (ggplot(df2) + geom_col(aes(x='letter',y='pos', fill='letter')) + geom_line(aes(x='letter', y='num_of_letters', color='letter'), size=1) + scale_color_hue(l=0.45) # some contrast to make the lines stick out + ggtitle('Greek Letter Analysis') )

Out[41]:

Folium


  • folium은 지도 데이터(Open Street Map)에 leaflet.js를 이용해 위치정보를 시각화하는 라이브러리입니다
  • 자바스크립트 기반이라 interactive하게 그래프를 그릴 수 있습니다
  • 한국 GeoJSON 데이터는 southkorea-maps에서 확인할 수 있습니다
  • 참고 자료
  • 그 외에도 pydeck, ipyleaflet 등으로 지도 시각화를 할 수 있습니다
  • 설치pip3 install folium

import folium print("folium version is", folium.__version__)

folium version is 0.6.0

m = folium.Map(location=[37.5502, 126.982], zoom_start=12) folium.Marker(location=[37.5502, 126.982], popup="Marker A", icon=folium.Icon(icon='cloud')).add_to(m) folium.Marker(location=[37.5411, 127.0107], popup="한남동", icon=folium.Icon(color='red')).add_to(m) m

Out[76]:

 

Plot.ly


  • plotly는 Interactive 그래프를 그려주는 라이브러리입니다
  • Scala, R, Python, Javascript, MATLAB 등에서 사용할 수 있습니다
  • 시각화를 위해 D3.js를 사용하고 있습니다
  • 사용해보면 사용이 쉽고, 세련된 느낌을 받습니다
  • Online과 offline이 따로 존재합니다(온라인시 api key 필요)
  • plotly cloud라는 유료 모델도 있습니다
  • 설치pip3 install plotly
  • 참고 자료

import plotly print("plotly version :", plotly.__version__)

plotly version : 3.1.1

plotly.offline.init_notebook_mode() plotly.offline.iplot({ "data": [{ "x": [1, 2, 3], "y": [4, 2, 5] }], "layout": { "title": "hello world" } })

 

11.522.5322.533.544.55Export to plot.ly »hello world

 

 

 

 

 

import plotly.figure_factory as ff import plotly.plotly as py import plotly.graph_objs as go df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/school_earnings.csv") table = ff.create_table(df) plotly.offline.iplot(table, filename='jupyter-table1')

Export to plot.ly »SchoolWomenMenGapMIT9415258Stanford9615155Harvard11216553U.Penn9214149Princeton9013747Chicago7811840Georgetown9413137Tufts7611236Yale7911435Columbia8611933Duke9312431Dartmouth8411430NYU679427Notre Dame7310027Cornell8010727Michigan628422Brown729220Berkeley718817Emory688214UCLA647814SoCal72819

 

 

 

 

 

data = [go.Bar(x=df.School, y=df.Gap)] plotly.offline.iplot(data, filename='jupyter-basic_bar')

MITStanfordHarvardU.PennPrincetonChicagoGeorgetownTuftsYaleColumbiaDukeDartmouthNYUNotre DameCornellMichiganBrownBerkeleyEmoryUCLASoCal0102030405060Export to plot.ly »

 

 

 

 

 

data = [dict( visible = False, line=dict(color='#ff0000', width=6), name = '𝜈 = '+str(step), x = np.arange(0,10,0.01), y = np.sin(step*np.arange(0,10,0.01))) for step in np.arange(0,5,0.1)] data[10]['visible'] = True steps = [] for i in range(len(data)): step = dict( method = 'restyle', args = ['visible', [False] * len(data)], ) step['args'][1][i] = True # Toggle i'th trace to "visible" steps.append(step) sliders = [dict( active = 10, currentvalue = {"prefix": "Frequency: "}, pad = {"t": 50}, steps = steps )] layout = dict(sliders=sliders) fig = dict(data=data, layout=layout) plotly.offline.iplot(fig, filename='Sine Wave Slider')

02468−1−0.500.51Export to plot.ly »Frequency: step-10step-0step-5step-10step-15step-20step-25step-30step-35step-40step-45

 

 

 

 

 

pyecharts


  • Baidu에서 데이터 시각화를 위해 만든 Echarts.js의 파이썬 버전입니다
  • 정말 다양한 그래프들이 내장되어 있어 레포트를 작성할 때 좋습니다!
  • 자바스크립트 기반이기 때문에 Interactive한 그래프를 그려줍니다
  • 공식 문서
  • 설치pip3 install pyecharts

import pyecharts print("pyecharts version : ", pyecharts.__version__)

pyecharts version : 0.5.8

attr = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] v1 = [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3] v2 = [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3] bar = pyecharts.Bar("Bar chart", "precipitation and evaporation one year") bar.add("precipitation", attr, v1, mark_line=["average"], mark_point=["max", "min"]) bar.add("evaporation", attr, v2, mark_line=["average"], mark_point=["max", "min"]) bar.height = 500 bar.width = 800 bar

Out[109]:

 

attr = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] v1 = [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3] v2 = [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3] bar = pyecharts.Bar("Bar chart", "precipitation and evaporation one year") bar.use_theme("dark") bar.add("precipitation", attr, v1, mark_line=["average"], mark_point=["max", "min"]) bar.add("evaporation", attr, v2, mark_line=["average"], mark_point=["max", "min"]) bar.height = 500 bar.width = 800 bar

Out[110]:

 

title = "bar chart2" index = pd.date_range("8/24/2018", periods=6, freq="M") df1 = pd.DataFrame(np.random.randn(6), index=index) df2 = pd.DataFrame(np.random.rand(6), index=index) dfvalue1 = [i[0] for i in df1.values] dfvalue2 = [i[0] for i in df2.values] _index = [i for i in df1.index.format()] bar = pyecharts.Bar(title, "Profit and loss situation") bar.add("profit", _index, dfvalue1) bar.add("loss", _index, dfvalue2) bar.height = 500 bar.width = 800 bar

Out[111]:

 

from pyecharts import Bar, Line, Overlap attr = ['A','B','C','D','E','F'] v1 = [10, 20, 30, 40, 50, 60] v2 = [38, 28, 58, 48, 78, 68] bar = Bar("Line Bar") bar.add("bar", attr, v1) line = Line() line.add("line", attr, v2) overlap = Overlap() overlap.add(bar) overlap.add(line) overlap

Out[112]:

 

from pyecharts import Pie attr = ['A','B','C','D','E','F'] v1 = [10, 20, 30, 40, 50, 60] v2 = [38, 28, 58, 48, 78, 68] pie = Pie("pie chart", title_pos="center", width=600) pie.add("A", attr, v1, center=[25, 50], is_random=True, radius=[30, 75], rosetype='radius') pie.add("B", attr, v2, center=[75, 50], is_randome=True, radius=[30, 75], rosetype='area', is_legend_show=False, is_label_show=True) pie

Out[113]:

 

bar = Bar("가로 그래프") bar.add("A", attr, v1) bar.add("B", attr, v2, is_convert=True) bar.width=800 bar

Out[114]:

 

import random attr = ["{}th".format(i) for i in range(30)] v1 = [random.randint(1, 30) for _ in range(30)] bar = Bar("Bar - datazoom - slider ") bar.add("", attr, v1, is_label_show=True, is_datazoom_show=True) bar

Out[115]:

 

days = ["{}th".format(i) for i in range(30)] days_v1 = [random.randint(1, 30) for _ in range(30)] bar = Bar("Bar - datazoom - xaxis/yaxis") bar.add( "", days, days_v1, is_datazoom_show=True, datazoom_type="slider", datazoom_range=[10, 25], is_datazoom_extra_show=True, datazoom_extra_type="slider", datazoom_extra_range=[10, 25], is_toolbox_show=False, ) bar

Out[116]:

 

3D

from pyecharts import Bar3D bar3d = Bar3D("3D Graph", width=1200, height=600) x_axis = [ "12a", "1a", "2a", "3a", "4a", "5a", "6a", "7a", "8a", "9a", "10a", "11a", "12p", "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p", "10p", "11p" ] y_axis = [ "Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday", "Sunday" ] data = [ [0, 0, 5], [0, 1, 1], [0, 2, 0], [0, 3, 0], [0, 4, 0], [0, 5, 0], [0, 6, 0], [0, 7, 0], [0, 8, 0], [0, 9, 0], [0, 10, 0], [0, 11, 2], [0, 12, 4], [0, 13, 1], [0, 14, 1], [0, 15, 3], [0, 16, 4], [0, 17, 6], [0, 18, 4], [0, 19, 4], [0, 20, 3], [0, 21, 3], [0, 22, 2], [0, 23, 5], [1, 0, 7], [1, 1, 0], [1, 2, 0], [1, 3, 0], [1, 4, 0], [1, 5, 0], [1, 6, 0], [1, 7, 0], [1, 8, 0], [1, 9, 0], [1, 10, 5], [1, 11, 2], [1, 12, 2], [1, 13, 6], [1, 14, 9], [1, 15, 11], [1, 16, 6], [1, 17, 7], [1, 18, 8], [1, 19, 12], [1, 20, 5], [1, 21, 5], [1, 22, 7], [1, 23, 2], [2, 0, 1], [2, 1, 1], [2, 2, 0], [2, 3, 0], [2, 4, 0], [2, 5, 0], [2, 6, 0], [2, 7, 0], [2, 8, 0], [2, 9, 0], [2, 10, 3], [2, 11, 2], [2, 12, 1], [2, 13, 9], [2, 14, 8], [2, 15, 10], [2, 16, 6], [2, 17, 5], [2, 18, 5], [2, 19, 5], [2, 20, 7], [2, 21, 4], [2, 22, 2], [2, 23, 4], [3, 0, 7], [3, 1, 3], [3, 2, 0], [3, 3, 0], [3, 4, 0], [3, 5, 0], [3, 6, 0], [3, 7, 0], [3, 8, 1], [3, 9, 0], [3, 10, 5], [3, 11, 4], [3, 12, 7], [3, 13, 14], [3, 14, 13], [3, 15, 12], [3, 16, 9], [3, 17, 5], [3, 18, 5], [3, 19, 10], [3, 20, 6], [3, 21, 4], [3, 22, 4], [3, 23, 1], [4, 0, 1], [4, 1, 3], [4, 2, 0], [4, 3, 0], [4, 4, 0], [4, 5, 1], [4, 6, 0], [4, 7, 0], [4, 8, 0], [4, 9, 2], [4, 10, 4], [4, 11, 4], [4, 12, 2], [4, 13, 4], [4, 14, 4], [4, 15, 14], [4, 16, 12], [4, 17, 1], [4, 18, 8], [4, 19, 5], [4, 20, 3], [4, 21, 7], [4, 22, 3], [4, 23, 0], [5, 0, 2], [5, 1, 1], [5, 2, 0], [5, 3, 3], [5, 4, 0], [5, 5, 0], [5, 6, 0], [5, 7, 0], [5, 8, 2], [5, 9, 0], [5, 10, 4], [5, 11, 1], [5, 12, 5], [5, 13, 10], [5, 14, 5], [5, 15, 7], [5, 16, 11], [5, 17, 6], [5, 18, 0], [5, 19, 5], [5, 20, 3], [5, 21, 4], [5, 22, 2], [5, 23, 0], [6, 0, 1], [6, 1, 0], [6, 2, 0], [6, 3, 0], [6, 4, 0], [6, 5, 0], [6, 6, 0], [6, 7, 0], [6, 8, 0], [6, 9, 0], [6, 10, 1], [6, 11, 0], [6, 12, 2], [6, 13, 1], [6, 14, 3], [6, 15, 4], [6, 16, 0], [6, 17, 0], [6, 18, 0], [6, 19, 0], [6, 20, 1], [6, 21, 2], [6, 22, 2], [6, 23, 6] ] range_color = ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'] bar3d.add( "", x_axis, y_axis, [[d[1], d[0], d[2]] for d in data], is_visualmap=True, visual_range=[0, 20], visual_range_color=range_color, grid3d_width=200, grid3d_depth=80, ) bar3d.width=700 bar3d.height=500 bar3d

Out[117]:

 

from pyecharts import Boxplot boxplot = Boxplot("Box plot") x_axis = ['expr1', 'expr2', 'expr3', 'expr4', 'expr5'] y_axis = [ [850, 740, 900, 1070, 930, 850, 950, 980, 980, 880, 1000, 980, 930, 650, 760, 810, 1000, 1000, 960, 960], [960, 940, 960, 940, 880, 800, 850, 880, 900, 840, 830, 790, 810, 880, 880, 830, 800, 790, 760, 800], [880, 880, 880, 860, 720, 720, 620, 860, 970, 950, 880, 910, 850, 870, 840, 840, 850, 840, 840, 840], [890, 810, 810, 820, 800, 770, 760, 740, 750, 760, 910, 920, 890, 860, 880, 720, 840, 850, 850, 780], [890, 840, 780, 810, 760, 810, 790, 810, 820, 850, 870, 870, 810, 740, 810, 940, 950, 800, 810, 870] ] _yaxis = boxplot.prepare_data(y_axis) boxplot.add("boxplot", x_axis, _yaxis) boxplot

Out[118]:

 

from pyecharts import Funnel attr = ["A", "B", "C", "D", "E", "F"] value = [20, 40, 60, 80, 100, 120] funnel = Funnel("퍼널 그래프") funnel.add( "퍼널", attr, value, is_label_show=True, label_pos="inside", label_text_color="#fff", ) funnel.width=700 funnel.height=500 funnel

Out[119]:

 

from pyecharts import Gauge gauge = Gauge("Gauge Graph") gauge.add("이용률", "가운데", 66.66) gauge

Out[120]:

 

 

카일스쿨 유튜브 채널을 만들었습니다. 데이터 사이언스, 성장, 리더십, BigQuery 등을 이야기할 예정이니, 관심 있으시면 구독 부탁드립니다 :)

이 글이 도움이 되셨다면 추천 클릭을 부탁드립니다 :)

 

출처 : 어쩐지오늘 https://zzsza.github.io/development/2018/08/24/data-visualization-in-python/

반응형

'Language > Python' 카테고리의 다른 글

파이썬으로 구글메일 보내기  (0) 2020.12.24
파이썬을 이용한 시스템 트레이딩  (0) 2016.08.04
728x90

import smtplib

from email.mime.text import MIMEText 

 

smtp = smtplib.SMTP('smtp.gmail.com'587)

smtp.ehlo()      # say Hello

smtp.starttls()  # TLS 사용시 필요

smtp.login('나의아이디@gmail.com''비밀번호'

 

msg = MIMEText('본문 테스트 메시지')

msg['Subject'= '테스트'

msg['To'= '보낼아이디@보낼메일주소.com'

smtp.sendmail('나의아이디@gmail.com''보낼아이디@보낼메일주소.com', msg.as_string())

 

smtp.quit()

반응형
728x90

1.1.4 PMD 이클립스 플러긴 사용법

 

 

(1) PMD 플러긴 설치

 

먼저 이클립스용 PMD 플러긴을 설치해보자.

 

 

Step 1 이클립스 실행

 

이클립스 실행 > Help > Install New So5ftware > Add 선택 > Repository 등록

 

 

Name: PMD

URL: http://pmd.sourceforge.net/pmd-4.3.0/integrations.html#eclipse

 

그림 7 이클립스용 PMD 플러긴 설치 -1

 

Step 2 PMD 플러긴 설치

 

발견된 PMD 플러긴 선택 > NEXT 클릭하여 설치 과정을 마친다.

 

 

그림 8 이클립스용 PMD 플러긴 설치 -2

 

Step 3 PMD 설치 확인

 

설치 과정이 완료되면 이클립스가 재 실행된다. PMD가 정상적으로 설치되면 Window > preferences 에서 확인 가능하다. 여기서 PMD 환경 설정을 할 수 있다.

 

 

그림 9 PMD 설치 확인

 

 

(2) Maven을 이용한 Webgoat-5.4 프로젝트 빌드

 

Webgoat 5.3이후부터는 Webgoat 소스코드 및 프로젝트는 메이븐(Maven)에 의해 관리된다. 

메이븐은 메이븐은 프로젝트 객체 모델(Project Object Model)이라는 개념을 바탕으로 프로젝트 의존성 관리, 라이브러리 관리, 프로젝트 생명 주기 관리 기능 등을 제공하는 프로젝트 관리 도구이다. 

또한 플러그인을 기반으로 소스 코드로부터 배포 가능한 산출물을 만들어 내는 빌드 기능 뿐만 아니라 레포팅 및 documentation 작성 기능 등을 제공한다. 

 

 

따라서 이클립스에 메이븐을 설치하고, 앞서 다운로드한 소스코드를 메이븐 프로젝트로 빌드하여야 이클립스에 정상적으로 프로젝트를 Import 할 수 있다.

 

 

Step 1 메이븐 설치

 

다음 경로에서 메이븐을 다운로드하여 원하는 곳에 압축해제 한다. 

(현재 최신 버전 3.3.3)메이븐 다운로드: http://maven.apache.org/download.cgi

 

 

그림 10 메이븐 다운로드

 

 

컴퓨터 > 속성 > 고급시스템속성 >고급탭 > 환경변수 > 시스템 변수 > 새로만들기

 

다음과 같이 입력한다.

 

그림 11 메이븐 환경변수 등록

 

 

또한 시스템 변수의 Path에서 %MAVEN_HOME%\bin;을 등록한다. 환경변수 등록이 완료되면 커맨드창에 [maven –version]을 입력해 메이븐이 정상적으로 실행되는지 확인한다.

 

그림 12 메이븐 설치 확인

 

 

Step 2 메이븐 플러긴 설치

 

이클립스 > Window > Install New Software > Add 클릭하여 다음과 같이 입력한다.

 

그림 13 메이븐 플러긴 설치

 

 

검색된 플러긴을 설치한다.

 

그림 14 메이븐 플러긴 설치

 

 

다시 한번 Help > Install New Software 에서 Work With란에 http://m2eclipse.sonatype.org/sites/m2e-extras 를 입력하여

 

검색된 플러긴 중 Maven Integration for Eclipse Extras'와 'Maven Integration for Eclipse WTP' 를 체크하여 설치한다.

 

 

그림 15 이클립스 플러긴 설치

 

 

설치가 완료되면 이클립스가 재부팅된다. 

이클립스에서 메이븐 플러긴 환경 설정을 위해 Window > preference > User Sertting > Browser 버튼 클릭 > 메이븐 설치 경로 이하 setting.xml 설정 후 적용

 

 

그림 16 메이븐 플러긴 환경 설정

 

Step 3 메이븐 프로젝트 Import

 

File > Import > Maven > Existing Maven project > browser > 소스코드 루트 디렉터리 설정

 

그림 17 메이븐 프로젝트 Import

 

정상적으로 Import 되면 다음과 같을 것이다.

 

그림 18 메이븐 프로젝트 Import

 

Step 4 PMD 실행

 

Project Explorer에 나타난 Webgoat-5.4프로젝트를 선택하고 오른쪽 팝업 메뉴에서 PMD > Check Code를 누르면 PMD가 자바 코드를 분석하기 시작한다. 

 

 

그림 19 PMD 실행

 

그림 20 PMD 실행

 

4 단계 결과 분석

 

코드 분석이 완료되면 PMD뷰로 자동전환 되면서 PMD 규칙에 위반된 코드를 표시한 결과가 나타난다. 

 

그림 21 PMD 코드 분석 결과

 

PMD 뷰에서 왼쪽 하단의 Violation Outline에서는 간략한 위반 규칙 내용을 확인할 수 있다.

PMD는 규칙의 우선순위를 1 단계에서 5단계로 분류하며 값이 낮을수록 높은 위험을 가지고 있다. 

 

 

그림 22 PMD 우선 순위 

 

 

위의 결과에서CrossSiteScripting > EditProfile.java 파일을 선택하면 Violation Outline 뷰에서 PMD 규칙에 위반된 코드를 PMD 규칙 우선 순위에 따라 필터링된 결과를 간략하게 살펴 볼 수 있다. 

규칙에 위반된 코드의 라인과 규칙명, 에러 메세지가 나타난다.

 

그림 23 PMD Violation Outline

 

각 세부 규칙 위반에 대한 내용을 확인하기 위해서는 Violation Outline 뷰에서 규칙 선택 후 오른쪽 팝업 메뉴에서 [Show details]를 누르면 된다.

 

 

그림 24 PMD Violation 세부 사항 확인-1

 

그림 25 PMD Violation세부 사항 확인-2

 

명명 규칙 집합에 해당되는 MethodNamingconventions 규칙에 위반된 결과이다. 

설명을 보면 메서드 이름은 항상 소문자로 시작되어야 한다는 규칙에 위배되었음을 알 수 있다. 해당 라인의 코드를 확인하면 내용이 일치함을 알 수 있다.

 

그림 26 코드 확인

 

PMD 뷰의 오른쪽 하단에는 PMD 관련된 여러 뷰를 추가하여 관련된 내용을 확인할 수 있다. 

관련 뷰를 추가하기 위해서는 Window > Show View > Other..> PMD > 뷰 선택하면 된다.

Violation Overview에서는 각 파일 별로 위반된 규칙 수를 확인할 수 있고, 규칙 우선 순위에 따라 필터링 할 수 있다. Blocker 우선 순위로 필터링된 결과이다.

 

 

그림 27 PMD Violation Overview

 

 

(3) Cut and Paste 코드 찾기

 

중복(Code and Paste)코드는 일반적으로 좋지 않은 계획과 팀 워크를 의미하며 찾기가 힘들다. 

PMD의 Copy/Paste Detector(CPD)는 중복코드를 찾을 수 있게 해준다. CPD는 PMD 설치 시 함께 제공된다.

이클립스에서는 Window > PMD > CPD Preferences > Launch CPD를 누르면 CPD가 실행된다.

 

그림 28 CPD 실행 예제

화면을 살펴보면 소스 디렉터리 경로를 설정하고(1), 몇 줄까지 중복될 때 중복코드로 처리할 것인가를 설정하고(2), 언어 설정 후(3), Go를 누르면 분석된다. 

 

 

(4) 보고서 생성

발견된 결과를 보고서로 생성할 수 있다.

Project Explorer > 프로젝트 선택 > PMD > Generate Report 

 

그림 29 보고서 생성

보고서 생성이 완료되면 Webgoat 메이븐 프로젝트에 reports라는 새로 생성된 디렉터리에 있다.

 

그림 30 보고서 생성

 

(5) PMD 커스텀마이징(Customizing)

 

PMD를 커스텀마이징 하는 가장 쉬운 방법은 기존의 규칙을 수정하는 것이다. 

새로운 규칙을 추가하는 것뿐만 아니라 불필요한 규칙을 제거할 수 있다. 그러나 이러한 일은 많은 지식이 필요하다. 각 PMD 규칙은 6가지 속성을 가진다.

 

속성 명

비고

Rule name

수정 불가능

Rule implementation class

수정 불가능

Priority

수정 가능, 정수형으로 1에서 5 범위를 가짐

Message

수정 가능, 문자형

Description

수정 가능, 문자형

Example

수정 가능, 문자형

표 6 PMD 규칙 속성

6가지 속성 중 Rule name과 Rule Implementation class는 사용자에 의해 변경할 수가 없다. 

규칙을 수정하기 전에 반드시 기존 설정을 백업하도록 한다.

 

1 단계 기존 규칙 백업하기

 

이클립스 > Window > Preferences > PMD > Rules Configuration > Import Selected Rules --> pmd-rules.xml 파일로 저장한다.

 

그림 31 PMD 규칙 백업

규칙을 수정하려면 수정할 규칙을 선택 후 수정 가능한 항목 탭을 수정하면 된다. 

아래 예는 SystemPrintin 규칙의 우선 순위를 1에서 5로 변경한 예이다.

 

 

그림 32 PMD 규칙 수정

 

(6) 새로운 규칙 추가

 

....

 

PMD 고급 사용법-http://www.eclipsezone.com/articles/pmd/

PMD 홈페이지-https://pmd.github.io/

PMD 문서-http://pmd.sourceforge.net/pmd-4.3.0/integrations.html#eclipse

Webgoat 소스코드 -https://code.google.com/p/webgoat/source/checkout

https://blog.idrsolutions.com/2015/04/creating-your-own-custom-pmd-rulesets/


반응형
728x90

1.1.3 커맨드라인 사용법

 

 

(1) PMD 실행 파일 다운로드

 

처음 PMD는 자립형(Standard-alone)으로 시작되었고, 현재 SourceForge.net 하에 오픈-소스 프로젝트로 운영되고 있다. 현재 PMD는 자바 통합개발환경을 지원하는데, JDeveloper, Eclipse, JEdit, JBuilder, Omnicore's CodeGuide, NetBeans/Sun Java Studio Enterprise/Creator, IntelliJ IDEA, TextPad, Maven, Ant, Gel, JCreator, and Emacs 에 대한 플러긴이 개발된 상태이다. 여기서는 Eclipse에 대한 PMD 플러긴을 다룬다.

 

 

 

현재 PMD 최신 버전은 5.4이며, 설치하려면 JDK 1.7 버전 이상이 필요로 한다. 다음 경로에서 다운로드 가능하며, PMD 홈페이지에서 PMD 관련 제품이나 책, 라이센스 정보, 사용 법 등에 대한 문서를 제공하고 있다.

 

 

PMD 다운로드: http://sourceforge.net/projects/pmd/files/

 

 

 

그림 1 PMD 실행 파일 다운로드

다운로드 압축 해제 하면 다음과 같을 것이다.

 

그림 2 PMD ZIP 파일 압축 해제

 

 

(2) Command 라인 사용법

 

Window 플랫폼 환경(Window 7 32bit)에서 커맨드 라인 사용법을 먼저 알아보자. 커맨드라인 pmd 도구는 ~bin 디렉터리에 있다. 

 

사용 문법은 다음과 같다.

 

 

사용 문법

pmd –d [파일이름 | 소스코드를 포함하고 있는 jar 혹은 ZIP 파일] –f [보고서이름] –R [규칙파일]

사용 예

C:\tmp\pmd-bin-5.4.0\pmd\bin>pmd -d c:\data\pmd\pmd\test-data\Unused1.java -f xml -R rulesets/java/unusedcode.xml

표 4 커맨드라인 사용 문법

 

PMD 실행 파일에는 Jar파일에 규칙 파일이 포함되어 있다.

사용되는 옵션들은 다음과 같으며 –help 옵션 사용 시 자세한 도움말을 보여준다.

 

 

그림 3 PMD help 옵션 예

 

옵션

설명

필수 유무

지원 언어

-rulesets / -R

사용할 룰셋 이름

O

 

-dir / -d

소스 루트 디렉터리

O

 

-format / -f

보고서 포맷, 디폴트 포맷은 'text'

X

 

-auxclasspath

소스코드에 사용되는 클래스 혹은 라이브러리 경로

X

 

-uri / -u

소스에 대한 데이터베이스 URI

X

plsql

-debug / -verbose / -D / -V

디버그 모드/ 많은 로그를 보여줌

X

 

-help / -h / -H

도움말

X

 

-encoding / -e

PMD가 진단하는 소스코드에 대한 인코딩방법 설정, 디폴트는 UTF-8

X

 

-benchmark / -b

벤치마크 모드

X

 

-stress / -S

스트레스 테스트 실행

X

 

-shortnames

보고서에 짧은 파일 이름을 출력함

X

 

-suppressmarker

Surpressed 규칙 위반을 보고서로 출력함

X

 

-minimumpriority / -min

규칙 우선 순위 처리

X

 

-property / -P

보고서 포맷에 대한 속성 정의

X

 

-reportfile / -r

보고서 결과물을 파일로 출력, 디폴트는 System.out

X

 

-version / -v

PMD에서 사용되는 언어 버전

X

 

-language / -l

PMD에서 사용되는 언어

X

 

-failOnViolation {true|false}

PMD는 규칙 위반 발견 시 4 상태로 존재한다. 이 옵션을 비활성화하면(false값) PMD가 종료되고(0) 보고서를 출력한다. 디폴트 true

X

 

표 5 PMD 명령 옵션

 

[실습 Webgoat 5.4 소스코드]

 

 

Step 1 Webgoat-5.4.war 파일 다운로드

 

다음 경로에서 Webgoat-5.4.war 파일을 다운로드 후 pmd 툴이 있는 디렉터리에서 압축 해제한다.

 

Webgoat 5.4 다운로드: https://code.google.com/p/webgoat/downloads/list

 

 

그림 4 Webgoat war 파일 다운로드

 

Step 2 PMD 실행 명령 입력

 

Webgoet-5.4 이름으로 디렉터리가 생성된다. 

Webgoat 소스 및 클래스 파일은 다음 경로에 있다.

 

 

~C:\pmd-bin-5.4.0\bin\WebGoat-5.4\WEB-INF\classes

위의 나열된 규칙 집합에서 java-basic을 적용하고 html 포맷의 파일로 점검 결과를 출력 해보자.

 

 

pmd.bat C:\pmd-bin-5.4.0\bin\WebGoat-5.4\WEB-INF\classes\org –f html –R java-basic –r PMD-java-basic-webgoat-5.4.html

 

 

그림 5 PMD 실행 명령

 

Step 3 결과파일 확인

 

생성된 결과 파일을 확인해 보자.

 

그림 6 결과파일 확인5

규칙 위반이 발견된 파일명과 라인, 문제를 보여준다. 

 

 

references

PMD 고급 사용법-http://www.eclipsezone.com/articles/pmd/

PMD 홈페이지-https://pmd.github.io/

PMD 문서-http://pmd.sourceforge.net/pmd-4.3.0/integrations.html#eclipse

Webgoat 소스코드 -https://code.google.com/p/webgoat/source/checkout

https://blog.idrsolutions.com/2015/04/creating-your-own-custom-pmd-rulesets/


반응형
728x90

1. JAVA 시큐어코딩가이드(안행부_2012.09)

 

1.1 제 1절 입력데이터 검증 및 표현

 

소프트웨어 개발 보안이란?

 

SW 개발과정에서 개발자 실수, 논리적 오류 등으로 SW에 내포될 수 있는 보안 취약점의 원인을 최소화하는 한편 안전한 SW를 개발하기 위한 일련의 보안 활동을 의미한다.

광의적 의미로는 SW 개발생명주기(SDLC:분석->설계->구현->테스트->유지보수)의 각 단계별로 요구되는 보안 활동을 의미하며 협의의 의미로는 구현단계에서 보안약점을 제거하기 위한 "시큐어코딩"을 의미한다.

 

국내의 경우 2009년부터 개발보안 관련 연구가 진행되면서 2012년 SW 보안약점 시범 진단을 수행되었으며 SW 보안약점 제거/조치 성과에 따라 2012년 6월에 행안부 "정보시스템 구축/운영/지침"이 개정/고시됨으로써 법적으로 의무화되었다. 또한 최근 2013년 개정/고시된 "안정행정부고시 제2013-26호"에 따르면 적용 대상이 확대 및 의무화되고 있다.

 

 

구분

설명

비고

대상

정보시스템 감리대상 정보화사업

단계적 확대

-2012.12월 사업규모 40억 이상

-2014.1월 사업규모 20억 이상

-2015.1월 감리대상 전사업

범위

소스코드(신규개발 전체, 유지보수로 변경된 부분)

상용 SW제외

기준

SW 보안약점 기준(SQL삽입등 47개 항목)

진단기준

진단도구

감리법인이 진단도구 사용시, 국정원장이 인증한 도구 사용

2014년 1월부터 적용

진단원

감리법인은 SW보안약점 진단 시, 진단원을 우선적으로 배치

감리대상외 사업은 자체적으로 SW보안약점 진단/제거 결과 확인

표 1 최근 SW 개발보안관련 법률 개정/고시

 

가이드 목적

 

정보시스템 구축/운영 지침에 따라 전자정부 관련 정보화사업 수행 시 안전한 SW 개발을 위한 Java 기반 시큐어코딩 기법 제시

 

가이드 구성

 

전자정부서비스 개발 시 가장 많이 사용되는 개발언어인 Java 기반의 정보시스템 개발 시 고려해야 할 보안 약점(83개)설명과 보안대책 이해를 위한 코딩 예제(Bad/Good)를 제시함

 

 

No

유형

설명

대표적 보안약점

1

입력데이터 

검증 및 표현

프로그램 입력값에 대한 검증 누락 혹은 부적절한 검증, 데이터의 잘못된 형식지정으로 발생할 수 있는 보안 약점

SQL 삽입, 크로스사이트 스크립팅 등 26개

2

보안 기능

보안기능(인증, 접근제어, 기밀성, 암호화, 권한관리등)을 적절하지 않게 구현 시 발생할 수 있는 보안약점

부적절한인가, 중요정보 평문저장 등 24개

3

시간 및 상태

동시 또는 거의 동시 수행을 지원하는 병렬 시스템, 하나 이상의 프로세스가 동작하는 환경에서 시간 및 상태를 부적절하게 관리하여 발생할 수 있는 보안 약점

경쟁조건, 제어문을 사용하지 않는 재귀함수 등 7개

4

에러처리

에러 처리하지 않거나, 불충분하게 처리하여 에러정보에 중요정보가 포함될때 발생할 수 있는 보안약점

취약한 패스워드 요구조건, 오류메시지를 통한 정보노출 등 4개

5

코드 오류

타입변환 오류, 자원(메모리 등)의 부적절한 반환 등과 같이 개발자가 범할 수 있는 코딩오류로 인해 유발되는 보안약점

널 포인터 역참조, 부적절한 자원해제 등 7개

6

캡슐화

중요한 데이터 또는 기능성을 불충분하게 캡슐화하였을 때 인가되지 않는 사용자에게 데이터 누출이 가능해지는 보안약점

제거되지 않고 남은 디버거코드, 시스템 데이터 정보노출등 8개

7

API 오용

의도된 사용에 반하는 방법으로 API를 사용하거나 보안에 취약한 API를 사용하여 발생할 수 있는 보안 약점

DNS Lookup에 의존한 보안결정, 널 매개변수 미조사 등 7개

표 2 안행부 7개분류 83개 보안약점

 

1.1.1 SQL 삽입

 

분류

입력 데이터 검증 및 표현

정의

-DB 와 연동된 웹 어플리케이션에서 입력 값 검증을 하지 않을 경우 공격자가 입력 폼 혹은 URL 파라미터에 SQL 구문을 삽입 및 실행하여 DB 정보를 열람하거나 조작할 수 있는 취약점을 말한다.

안전한 코딩기법

-PreparedStatememt 클래스와 하위 메서드 executeQuery(), execute(), executeUpdate()를 사용한다.

-PreparedStatement를 사용할 수 없다면 입력값 필터링 처리를 적용한다. 필터링 기준은 SQL 구문 제한, 특수문자 제한, 길이제한 등을 복합적으로 사용한다.

표 3 SQL 삽입

 

1.1.2 자원 삽입(Improper Control of Resource Identifier)

 

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값을 검증하지 않고 시스템자원에 대한 식별자로 사용하는 경우 공격자는 입력 값 조작을 통해 시스템이 보호하는 자원에 임의로 접근하거나 수정할 수 있고 잘못된 입력값으로 시스템 자원 사이에 충돌이 발생할 수 있다.

안전한 코딩기법

-외부 입력 값을 자원(파일, 소켓의 포트) 식별자로 사용하는 경우, 적절한 검증을 거치도록 하거나 사전에 정의된 리스트(화이트리스트 방식)에서 선택되도록 작성한다.(단, 화이트리스트에 위험한 자원이 포함되어서는 안 된다.)

-외부 입력 값이 파일이 경우 경로 탐색(Directory Traversal) 문자를 제거한다. 

표 4 자원 삽입

1.1.3 크로스 사이트 스크립트(Cross Site Scripting)

분류

입력 데이터 검증 및 표현

정의

-검증되지 않은 외부 입력이 동적 웹페이지 생성에 사용될 경우 전송된 동적 웹 이지를 열람하는 접속자의 권한으로 부적절한 스크립트가 실행될 수 있다.

안전한 코딩기법

-Reflected XSS의 경우 사용자 입력 값에서 <,>,&,',"와 같은 특수 문자를 문자변환함수나 메서드를 사용하여 이스케이프처리한다.

-Stored XSS의 경우, 즉 HTML 태그를 지원해야 하는 게시판에서는 사전에 정의된 리스트(화이트리스트방식)만 허용되도록 한다.(단, 화이트리스트에 위험한 태그가 포함되어서는 안 된다.)

- 보안성이 검증된 API를 사용하여 위험한 문자열을 제거한다.

표 5 XSS

 

OSWASP에서 제공하고 있는 보안 API: https://www.owasp.org/index.php/Esapi#tab=Downloads

특수 문자를 이용한 공격 스크립트와 같은 외부 입력 문자열을 이용한 공격을 효과적으로 차단할 수 있다. 다운로드 링크로 접속하여 Java 용 ESAAPI를 다운로드 하면된다.

 

 

그림 1 OWASP XSS 보안 API

그림 2 OWASP XSS 보안 API

 

 

또 다른 보안 XSS 보안 API는 josephconnell에서 제공하는 API가 있다.

josephconnell에서 제공하고 있는 보안 API: http://josephoconnell.com/java/xss-html-filter/

 

그림 3 OWASP XSS 보안 API

 

 

1.1.4 운영체제 명령어 삽입(OS Command Injection)

분류

입력 데이터 검증 및 표현

정의

-적절한 입력 값 검증을 거치지 않은 사용자 입력 값이 운영체제 명령 일부 혹은 전부로 구성되어 있는 경우 시스템 명령이 실행되어 권한 상승이나 시스템 동작 및 운영에 영향을 미칠 수 있다. 

안전한 코딩기법

-웹 인터페이스를 통해 서버내부로 시스템 명령어를 전달시키지 않도록 어플리케이션을 구성한다.

-외부에서 전달되는 값을 그대로 시스템 내부 명령어로 사용하지 않는다.

-외부에서 시스템 명령어를 전달받아야 하는 경우 사전에 정의된 리스트(화이트리스트 방식: 단 화이트리스트에 위험한 명령어가 포함되어서는 안 된다)만 적용되도록 한다.

그림 4 OS 커맨드 인젝션

 

1.1.5 위험한 형식파일 업로드(Unrestricted Upload of File with Dangerous Type)

분류

입력 데이터 검증 및 표현

정의

-서버측에서 실행될 수 있는 스크립트 파일(asp,aspx,jsp,php)이 업로드 및 실행가능 할 경우 공격자가 시스템 내부 명령어를 실행하거나 외부와 연결하여 시스템을 제어할 수 있다.

안전한 코딩기법

-업로드 파일의 타입과 크기를 제한하고 업로드 디렉터리를 웹 서버의 다큐먼트에 외부에 설정한다.

업로드 파일 타입 설정 시 사전에 정의된 리스트(화이트리스트방식:단 화이트리스트에 위험한 확장자가 포함되어서는 안된다.)만 업로드 되도록 하고, 확장자도 대소문자 구분 없이 처리하도록 한다.

-공격자의 웹을 통한 직접 접근을 차단한다.

-업로드 디렉터리의 파일 실행 여부를 설정할 수 있는 경우 실행 속성을 제거한다.

그림 5 위험한 형식의 파일 업로드

 

1.1.6 신뢰되지 않는 URL 주소로 자동 접속 연결(URL Redirection to Untrusted Site, Open Redirect)

분류

입력 데이터 검증 및 표현

정의

-사용자로부터 입력되는 값을 리다이렉션 파라미터의 값으로 사용하는 경우 적절한 입력 값 검증이 없으면 피싱(phishing)공격에 노출될 수 있다.

안전한 코딩기법

-리다이렉션 파라미터의 값은 사전에 지정된 리스트(화이트리스트방식)로 관리하고 검증한 다음 연결되도록 한다.

그림 6 Open Redirection

 

1.1.7 XQuery 삽입(XQuery Injection)

분류

입력 데이터 검증 및 표현

정의

-XQuery를 사용하여 XML 데이터에 대한 동적 쿼리를 생성할 때 사용하는 외부 입력 값에 대한 적절한 입력 값 검증이 없으면 공격자 쿼리 구문을 임의로 조작하여 XML DB를 조회하거나 조작할 수 있다.

안전한 코딩기법

-XQuery에 사용되는 외부 입력 값에 대하여 특수 문자 및 쿼리 예약어를 화이트 리스트 방식(단 화이트리스트에 위험한 예약어가 포함되서는 안된다)으로 필터링하고 XQuery에 사용되는 쿼리문은 스트링을 연결하는 형태로 구성하지 않고 파라미터화된 쿼리문을 사용한다.

표 6 XQuery 삽입

 

1.1.8 XPath 삽입(XPath Injection)

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값 검증 없이 외부 입력 값을 XPath 쿼리문 생성을 위한 문자열로 사용하게 되면 공격자에 의해 조작된 쿼리문이 생성 및 실행되어 인가되지 않은 데이터를 열람할 수 있다.

안전한 코딩기법

-XPath 사용되는 외부 입력 값에 특수문자(", [, ], /, =, @ 등) 및 쿼리 예약어를 화이트리스트 방식(단 화이트리스트에 위험한 예약어가 포함되어서는 안된다)으로 필터링하고 파라미터화된 쿼리문을 지원하는 XQuery를 사용한다. 

표 7 XPath 삽입

 

1.1.9 LDAP 인젝션(LDAP Injection)

분류

입력 데이터 검증 및 표현

정의

-LDAP 쿼리문이나 결과에 외부 입력 값이 부분적으로 적절한 검증 없이 사용되면 공격자는 조작된LDAP 쿼리문을 실행 할 수 있다.

안전한 코딩기법

-위험문자에 대한 검증 없이 외부 입력 값을 LDAP 질의어 생성에 사용하면 안된다.

-DN과 필터에 사용되는 사용자 입력 값에 특수문자(DN에 사용되는 특수문자 '\', 필터에 사용되는 특수문자 '=, +, <, >,# , ;, \')는 이스케이프 처리하여 특수문자가 아닌 일반 문자로 처리되도록 한다.

표 8 LDAP 삽입

 

1.1.10 크로스사이트 요청 위조(Cross-Site Request Forgery)

분류

입력 데이터 검증 및 표현

정의

-특정 웹 사이트에 대해 사용자가 인지하지 못한 상황에서 사용자의 의도와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)의 요청을 하게 하는 공격을 말한다. 

안전한 코딩기법

-입력화면 폼 작성 시 GET 방식보다는 POST 방식을 사용한다.

-입력화면 폼과 해당 입력을 처리하는 프로그램 사이에 토큰을 사용하여 공격자의 직접적인 URL 사용이 동작하지 않도록 처리한다.

-특히 중요한 기능에 대해서는 사용자 세션 검증과 재 인증을 유도한다.

표 9 CSRF

 

1.1.11 디렉터리 경로 조작(Path Traversal)-상대 디렉터리 경로 조작(Relative Path Traversal)

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값에 의해 "디렉터리 경로 문자열"이 생성될 경우 입력 값 검증이 적절하게 이루어지지 않으면 공격자에 의해 디렉터리 경로가 조작되어 시스템 정보 누출 혹은 서비스 장애 등의 위험이 발생할 수 있다.

안전한 코딩기법

-외부 입력 값으로 파일 디렉터리 경로가 생성되지 않도록 한다. 필요 시에는 외부 입력 값에 경로 탐색 문자(",/,\)를 필터링 한다.

-외부의 입력을 받아 들이되 내부적인 처리는 미리 정의해놓은 데이터를 사용하도록 코딩한다.

표 10 상대 디렉터리 경로 조작

 

1.1.11 디렉터리 경로 조작(Path Traversal)-절대 디렉터리 경로 조작(Absolute Path Traversal)

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값이 파일 시스템을 조작하는 경로를 직접 제어할 수 있거나 영향을 끼치면 위험하다. 사용자 입력 값이 파일 시스템 작업에 사용되는 경로를 제어하는 것을 허용하면 공격자가 응용프로그램에 치명적인 시스템 파일 또는 일반 파일을 접근하거나 변경할 수 있다.

안전한 코딩기법

-외부 입력 값을 통해 파일이름 생성  접근을 허용하지 말고외부 입력에 따라접근이 허용된 파일의 리스트에서 선택하도록 한다.

표 11 절대 디렉터리 경로 조작

 

1.1.12 HTTP 응답 분활(HTTp Response Splitting)

분류

입력 데이터 검증 및 표현

정의

-사용자 입력 값이 HTTP 응답 헤더에 포함되어 사용자에게 다시 전달될 경우 입력 값에 CRLF(Carriage Return, Line Feed, 개행문자) 특수 문자가 필터링이 없으면 HTTP 응답이 분활되어 실행될 수 있다. 이 경우 공격자는 개행문자를 이용하여 첫번째 응답을 종료 시키고 두번째 응답에 악의적인 코드를 삽입하여 실행 시킬 수 있다.

안전한 코딩기법

-외부 입력 값을 HTTP 응답 헤더에 포함시킬 때 CRLF를 필터링하거나 적절한 인코딩기법을 적용한다.

표 12 HTTP 응답 분활

 

1.1.13 정수 오버플로우(Integer Overflow/Wraparound)

분류

입력 데이터 검증 및 표현

정의

-정수형 변수의 오버플로우는 정수값이 증가하면서 Java에서 허용된 가장 큰 값보다 더 커져서 실제 저장되는 값은 의도하지 않게 아주 작은 수이거나 음수가 될 수 있다. 특히 반복문 제어, 메모리 할당, 메모리 복사 등을 위한 조건으로 사용자가 입력 값을 사용하고 그 과정에서 정수 오버플로우가 발생하는 경우 보안상 문제를 유발할 수 있다.

안전한 코딩기법

-언어/플랫폼 별 정수타입의 범위를 확인하여 사용한다. 정수형 변수를 연산에 사용하는 경우 결과값이 범위 체크하는 모듈을 사용한다. 

-특히 외부 입력값을 동적으로 할당하여 사용하는 경우 변수의 값 범위를 적절한 범위내 존재하는지 확인한다.

표 13 정수 오버플로우

 

1.1.14 보호 메커니즘을 우회할 수 있는 입력값 변조(Reliance on Untrusted Input in a Security Decision)

분류

입력 데이터 검증 및 표현

정의

-인증이나 인가와 같은 보안 결정이 입력 값(쿠키, 환경 변수, 히든 필드)에 기반으로 수행되는 경우 공격자는 입력 값을 조작하여 응용프로그램의 보안을 우회할 수 있음

안전한 코딩기법

-상태 정보나 민감한 데이터 특히 사용자 세션정보와 같은 중요 정보는 서버에 저장하고 보안 확인 절차도 서버에서 실행한다.

-보안설계 관점에서 신뢰할 수 없는 입력 값이 어플리케이션 내부로 들어올 수 있는 지점과 보안결정에 사용되는 입력 값을 식별하고 제공되는 입력 값에 의존할 필요가 없는 구조로 변경할 수 있는지 검토한다.

표 14 보호 메커니즘 우회 

 

1.1.15 SQL삽입공격: JDO(SQL Injection JDO)

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값을 적절한 검증 없이 JDO(Java Date Object) API의 SQL 혹은 JDOQL 질의문 생성을 위한 문자열로 공격자 의도한 조작된 질의문이 생성 및 실행될 수 있다. 

안전한 코딩기법

-JDO 질의문 생성시에는 상수 문자열만을 사용하고 Query.execute() 실행 시 파라미터화된 쿼리문을 사용한다.

표 15 SQL 삽입:JDO

 

1.1.16 SQL삽입공격: Persistence(SQL Injection Persistence)

분류

입력 데이터 검증 및 표현

정의

-J2EE Persistence API를 사용하는 응용프로그램에서 외부 입력값을 적절한 검증 없이 사용하면 공격자가 의도한 조작된 질의문이 생성 및 실행될 수 있다.

안전한 코딩기법

-질의문 생성 시 상수 문자열만을 사용하고 Javax.persistence.Query.setParameter() 메서드를 사용하여 인자값을 설정한다.

표 16 SQL삽입:Persistence

 

1.1.17 SQL삽입공격: mybatis Data Map(SQL Injection mybatis Map)

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값이 질의어의 인자값으로만 사용되지 않고 질의 명령어에 연결되는 문자열로 사용되면 공격자가 의도한 조작된 질의문이 생성 및 실행될 수 있다.

안전한 코딩기법

-외부 입력으로부터 위험 문자나 의도하지 않았던 입력을 제거하는 코드를 삽입한다.

-mybatis Data Map 파일의 인자를 받는 질의 명령어 정의시에 문자열 삽입 인자($...$)를 사용하지 않는다. 즉 #<인자이름># 형태의 질의문을 사용한다.

표 17 SQL삽입:mybatis Data Map

 

1.1.18 LDAP 처리(LDAP Manipulation)

분류

입력 데이터 검증 및 표현

정의

-LDAP 질의문이나 결과로 외부 입력값이 적절한 검증없이 사용되면 LDAP 질의문이 실행될 때 공격자가 의도한 조작된 질의문이 생성 및 실행될 수 있다.

안전한 코딩기법

-외부 입력 값에 대한 유효성 검증 후 사용해야 하며 LDAP 사용 시 질의문을 제한하여 허용된 레코드만 접근하도록 해야 한다.

표 18 LDAP 처리

1.1.19 시스템 혹은 구성 설정의 외부제어(External Control of System or Configuration Setting)

분류

입력 데이터 검증 및 표현

정의

-시스템 설정이나 구성 요소를 외부에서 제어할 수 있으면 공격자에 의해 악용될 위험이 있다.

안전한 코딩기법

-외부 입력을 Connection.setCatalog() 메서드의 인자 값을 생성하는데 사용하지 않도록 한다. 불가피하게 사용해야 한다면 외부 입력을 화이트리스트 방식으로 관리 한다.

표 19 시스템 혹은 구성 설정의 외부 제어

 

1.1.20 크로스 사이트 스크립팅:DOM

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값이 적절한 검증 없이 웹 페이지 생성에 사용되면 악의적인 HTML 스크립트 코드가 클라이언트에게 실행 될 수 있다.

안전한 코딩기법

-JSP의 document.write()와 같이 JSP의 DOM 객체 출력을 수행하는 메서드 인자 값을 외부 입력 값으로 사용할 경우 위험 문자를 필터링 하여야 한다.

-보안 API로 위험 문자를 제거한다.

표 20 DOM-XSS

 

1.1.21 동적으로 생성되어 수행되는 명령어 삽입(Eval Injection)

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값이 적절한 검증 없이 동적으로 수행되는 스크립트 혹은 프로그램 명령어로 사용되면 공격자가 원하는 임의의 작업을 수행할 위험이 있다.

안전한 코딩기법

-외부 입력이 eval()함수의 인자로 사용될 경우 외부 입력 값에서 위험 문자를 제거한다.

-ESAPI for Javascruipt 등의 보안 API를 사용하여 외부 입력 값을 검증한다.

표 21 Eval Injection

 

1.1.22 프로세스 제어(Process Control)

분류

입력 데이터 검증 및 표현

정의

-신뢰되지 않은 소스나 신뢰되지 않은 환경으로부터 라이브러리를 적재하거나 명령을 실행하면 악의적인 코드가 실행될 위험이 있다.

안전한 코딩기법

-프로그램에서 라이브러리 적재 시 절대 경로를 사용한다.

표 22 프로세스 제어

1.1.23 안전하지 않은 리플렉션(Unsafe Reflection)

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값을 동적 클래스 적재 시 인자로 받을 경우 적절한 검증이 없으면 악의적인 클래스가 적재 및 실행될 위험이 있다.

안전한 코딩기법

-외부 입력 값을 적재할 클래스로 입력 받지 않고 사전에 지정한 화이트리스트 방식에 의해 관리한다.

표 23 안전하지 않은 리플렉션

 

1.1.24 무결성 점검 없는 코드 다운로드(Code without Intergrity Check)

분류

입력 데이터 검증 및 표현

정의

-원격으로부터 소스 코드 혹은 실행 파일을 무결성 검증 없이 다운로드 시 host server 변조 혹은 DNS spoofing 혹은 전송 시 소스코드 변조로 공격자가 의도한 공격이 실행될 위험이 있다.

안전한 코딩기법

-SW 자동 업데이트와 같이 다운로드에 대한 코드 제공 시에는 코드에 대한 암호화 시그니처를 사용하고 클라이언트가 시그니처를 검증하도록 한다.

표 24 무결성 점검 없는 코드 다운로드

1.1.25 SQL 삽입공격:Hibrate

분류

입력 데이터 검증 및 표현

정의

-외부 입력 값을 적절한 검증 없이 Hibrate API의 SQL 질의문 생성을 위한 문자열로 사용할 경우 공격자가 의도한 질의문을 생성 및 실행할 위험이 있다.

안전한 코딩기법

-질의문 생성 시 상수 문자열만을 사용한다. 

표 25 SQL Injection:Hibrate

 

1.1.26 보안결정을 신뢰할 수 없는 입력 값에 의존(Reliance on Untrusted Input in a Security Decision)

분류

입력 데이터 검증 및 표현

정의

-인증이나 인가와 같은 보안 결정이 입력 값(쿠키, 환경 변수, 히든 필드)에 기반으로 수행되는 경우 공격자는 입력 값을 조작하여 응용프로그램의 보안을 우회할 수 있음

안전한 코딩기법

-상태 정보나 민감한 데이터 특히 사용자 세션정보와 같은 중요 정보는 서버에 저장하고 보안 확인 절차도 서버에서 실행한다.

-보안설계 관점에서 신뢰할 수 없는 입력 값이 어플리케이션 내부로 들어올 수 있는 지점과 보안결정에 사용되는 입력 값을 식별하고 제공되는 입력 값에 의존할 필요가 없는 구조로 변경할 수 있는지 검토한다.

표 26 보안결정을 신뢰할 수 없는 입력 값에 의존

 

refers

http://codedragon.tistory.com/1212(안전행정부고시)

 

http://www.securitya.kr/eduwiz/bb/bbs/board.php?bo_table=c403&wr_id=12


반응형
728x90

LOG4J

 

 

I. 들어가면서.. 그리고 log4j

 

log4j는 자바 어플리케이션에서 빠르고 효과적으로 로깅 할 수 있도록 도와주는 오픈 소스 프로젝트입니다.

 

로깅(logging)은 코드의 가독성을 떨어뜨리는 단점이 있지만 애플리케이션에 문제가 있을 때 개발자가 자세한 상황을 파악할 수 있도록 해 주며 테스팅시 빠질 수 없는 요소입니다.


아마도 여러분들은 여러 어플리케이션이 추가되면서 각 개발자들만의 독특한 로깅방식이 서로 썩이고 얽혀서 화면에 나타나는것을 많이 봤을겁니다 -_-;
즉 로깅방법을 통일할 필요가 있는것이죠. 모든 개발자가 특정 포맷에 맞추어서 로깅 한다면 한결 로깅하기도 편하겠지요


오픈 소스 프로젝트인 Log4j는 개발자들이 매우 손쉽고 다양한 형태로 로깅을 할 수 있도록 도와줍니다. 성능또한 우수해 더이상 System.out.println을 사용할 필요가 없습니다.

 

 

II. 다운로드

 

다운로드 http://logging.apache.org/log4j/docs/download.html

매뉴얼 http://logging.apache.org/log4j/docs/documentation.html

API spec http://logging.apache.org/log4j/docs/api/index.html

 

 

III. LOG4J 구조

 

일단 log4j를 잘 모르지만 그 구조만 살짝 살펴보고 넘어갑시다

log4j는 크게 3가지 요소로 구성되며 그 구조는 다음과 같습니다

① Logger(Category) : 로깅 메세지를 Appender에 전달합니다.

② Appender : 전달된 로깅 메세지를 파일에다 기록할 것인지, 콘솔에 출력할 것인지

                   아니면 DB에 저장할 것인지 매개체 역활을 합니다.

③ Layout : Appender가 어디에 출력할 것인지 결정했다면 어떤 형식으로 출력할 것이지

                출력 layout을 결졍합니다.

쉽죠?

 

 

IV. LOG4J 로깅 레벨

 

log4j는 다양한 로깅레벨을 지원합니다.

 

① FATAL : 가장 크리티컬한 에러가 일어 났을 때 사용합니다.

② ERROR : 일반 에러가 일어 났을 때 사용합니다.

③ WARN : 에러는 아니지만 주의할 필요가 있을 때 사용합니다.

④ INFO : 일반 정보를 나타낼 때 사용합니다.

⑤ DEBUG : 일반 정보를 상세히 나타낼 때 사용합니다.

 

만약 로깅 레벨을 WARN 으로 설정하였다면 그 이상 레벨만 로깅하게 됩니다.

즉 WARN, ERROR, FATAL 의 로깅이 됩니다.

 

 

V. 샘플코드 1

 

jsp에서 사용하는 예제가 없어 만들어 봤습니다.

 

test.jsp

 

<%@ page contentType="text/html;charset=MS949"
  import!="org.apache.log4j.Logger" %>

<%!
 static Logger logger = Logger.getLogger("test.jsp");
%>

<%
 logger.fatal("fatal!!");

 logger.fatal("fatal2!!", new NullPointerException("널입니다요"));

 logger.error("error!", new NumberFormatException());

 logger.error("error!2");

 logger.warn("warn");

 logger.info("info");

 logger.debug("debug");
%>

 

 

결과 콘솔화면

 

 

 

 

 

 

 

 static Logger logger = Logger.getLogger("test.jsp");

static 메소드 getLogger를 통해 logger 인스턴스를 가져옵니다. 
getLogger에는 파라미터로 스트링 혹은 클래스를 사용하는데 jsp에서는 클래스를 파라미터로 주기에는 좀 애매합니다. 그냥 스트링으로 주도록 하지요

 

 logger.fatal("fatal!!");
logger.fatal("fatal2!!", new NullPointerException("널입니다요"));
   
logger에 fatal 레벨의 메세지를 전달합니다.

다음 두가지 메소드를 지원하는군요

fatal(Object message)

fatal(Object message, Throwable t)

각 레벨마다 위처럼 두가지 메소드를 지원합니다.

 

지원 메쏘드
logger.fatal(Object message)logger.fatal(Object message, Throwable t)
logger.error(Object message)logger.error(Object message, Throwable t)
logger.warn(Object message)logger.warn(Object message, Throwable t)
logger.info(Object message)logger.info(Object message, Throwable t)
logger.debug(Object message)logger.debug(Object message, Throwable t)

 

 

VI. 샘플코드 2

 

서블릿의 경우 다음과 같이 코딩하면 되겠군요

TestServlet.java

 

import! javax.servlet.*;
import! javax.servlet.http.*;
import! org.apache.commons.logging.Log;
import! org.apache.commons.logging.LogFactory;

public class TestServlet extends HttpServlet {


    static Logger logger = Logger.getLogger(TestServlet.class);

 

    public void init(ServletConfig config) throws ServletException {
         super.init(config);
    }

 

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

         try {
              ...
   
              logger.info("Hellow World~");

              ...

          } catch (Exception e) {
              logger.error("Error at TestServlet", e);
          }
     }
}

 

 

VII. LOG4J 설정

 

log4j 설정은 프로그램 내에서 할 수 있지만 설정파일을 사용함으로서 좀더 유연하게 log4j환경을 만들 수 있습니다.

 

① 프로그램에서 설정

<%@ page contentType="text/html;charset=MS949"
  import!="org.apache.log4j.*,java.io.* "
%>

<%!
 static Logger logger = Logger.getLogger("log4j.jsp");
%>

<%
 String layout = "%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n";
 String logfilename = "DailyLog.log";
 String datePattern = ".yyyy-MM-dd ";

 PatternLayout patternlayout = new PatternLayout(layout);
  DailyRollingFileAppender appender = new DailyRollingFileAppender(patternlayout, logfilename, datePattern);
  logger.addAppender(appender);
 logger.setLevel(Level.INFO); 
  logger.fatal("fatal!!");
%>


② property 파일에 설정
log4j.properties를 만들어 /WEB-INF/classes 밑에 놓으세요

 

 

log4j.rootLogger=INFO, stdout, rolling

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n

log4j.appender.rolling=org.apache.log4j.DailyRollingFileAppender

log4j.appender.rolling.File=output.log

log4j.appender.rolling.Append=true

log4j.appender.rolling.MaxFileSize=500KB

log4j.appender.rolling.DatePattern='.'yyyy-MM-dd

log4j.appender.rolling.layout=org.apache.log4j.PatternLayout

log4j.appender.rolling.layout.ConversionPattern=%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n

 

#최상위 카테고리에 INFO로 레벨 설정 및 appender로 stdout, rolling을 정의
log4j.rootLogger=INFO, stdout, rolling

#stdout 어펜더는 콘솔에 뿌리겠다는 정의
log4j.appender.stdout=org.apache.log4j.ConsoleAppender

#stdout 어펜더는 patternlayout을 사용하겠다는 정의

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#페턴은 다음과 같이 포맷팅 하겠다는 것을 정의

log4j.appender.stdout.layout.ConversionPattern=%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n

 

#역시나 rolling 어펜더는 파일로 처리한다라고 정의
log4j.appender.rolling=org.apache.log4j.DailyRollingFileAppender

#로그 파일 이름은 output.log
log4j.appender.rolling.File=output.log

#true면 톰캣을 내렸다 올려도 파일이 리셋되지 않습니다.
log4j.appender.rolling.Append=true

#파일 최대 사이즈는 500KB로 설정
log4j.appender.rolling.MaxFileSize=500KB

#파일 포맷은 output.log.2005-03-10 으로 관리하겠다고 정의
log4j.appender.rolling.DatePattern='.'yyyy-MM-dd

#역시나 rolling 어펜더는 패턴 레이아웃을 사용하겠다고 정의
log4j.appender.rolling.layout=org.apache.log4j.PatternLayout

#rolling 어펜더는 패턴 레이아웃 포맷
log4j.appender.rolling.layout.ConversionPattern=%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n

 

 

VIII. 설정 포맷

 

 로그파일명 포맷 (DatePattern)
로그파일명 포맷입니다. 날짜, 시간 및 분단위로까지 로그 파일을 분리할 수 있습니다.

형식설명
'.'yyyy-MM매달 첫번째날에 로그파일을 변경합니다
'.'yyyy-ww매주의 시작시 로그파일을 변경합니다.
'.'yyyy-MM-dd매일 자정에 로그파일을 변경합니다.
'.'yyyy-MM-dd-a자정과 정오에 로그파일을 변경합니다.
'.'yyyy-MM-dd-HH매 시간의 시작마다 로그파일을 변경합니다.
'.'yyyy-MM-dd-HH-mm매분마다 로그파일을 변경합니다.



② PatternLayout 포맷
로그자체를 어떤 포맷으로 남길지 결정합니다.
layout에는 HTMLLayout, PatternLayout, SimpleLayout, XMLLayout등이 있으며 PatternLayout이 일반적으로 가장 많이 쓰입니다.

 

형식설명
%pdebug, info, warn, error, fatal 등의 priority 가 출력된다.
%m로그내용이 출력됩니다
%d로깅 이벤트가 발생한 시간을 기록합니다.
포맷은 %d{HH:mm:ss, SSS}, %d{yyyy MMM dd HH:mm:ss, SSS}같은 형태로 사용하며 SimpleDateFormat에 따른 포맷팅을 하면 된다
%t로그이벤트가 발생된 쓰레드의 이름을 출력합니다.
%%% 표시를 출력하기 위해 사용한다.
%n플랫폼 종속적인 개행문자가 출력된다. \r\n 또는 \n 일것이다.
%c카테고리를 표시합니다 
예) 카테고리가 a.b.c 처럼 되어있다면 %c{2}는 b.c가 출력됩니다.
%C클래스명을 포시합니다. 
예) 클래스구조가 org.apache.xyz.SomeClass 처럼 되어있다면 %C{2}는 xyz.SomeClass 가 출력됩니다
%F로깅이 발생한 프로그램 파일명을 나타냅니다.
%l로깅이 발생한 caller의 정보를 나타냅니다
%L로깅이 발생한 caller의 라인수를 나타냅니다
%M로깅이 발생한 method 이름을 나타냅니다.
%r어플리케이션 시작 이후 부터 로깅이 발생한 시점의 시간(milliseconds)
%x로깅이 발생한 thread와 관련된 NDC(nested diagnostic context)를 출력합니다.
%X로깅이 발생한 thread와 관련된 MDC(mapped diagnostic context)를 출력합니다.

 

예시) (같은 색끼리 보시면 됩니다)

위의 test.jsp를 다음 포맷으로 출력해본다면

[%c] [%C] [%d] [%F] [%l] [%L] [%m] [%M] [%n] [%p] [%r] [%t] [%x] [%X]는 다음과 같다

[test.jsp] [org.apache.jsp.test_jsp] [2005-03-10 12:37:23,561] [test_jsp.java][org.apache.jsp.test_jsp._jspService(test_jsp.java:64)] [64] [fatal!!] [_jspService] [개행] [FATAL] [765567] [http-8080-Processor25] [] []

 

=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

 

 

 

기본적인 log4j.properties와 간단한 사용법

아직도 System.out.println()으로 디버그용 메시지를 화면에 출력한다면,

이제 삽질 그만하고 로깅 API들을 사용해 볼 것을 권장하고 싶다.

그 중에서도 난 Log4j를 사용한다. (사실 이거밖에 모른다... ;) )

혹여 log4j.properties 설정이 귀찮아서 Log4J를 사용하지 않는다면

다음의 기본적인 log4j.properties를 사용해보자.

이것만으로도 System.out.println과는 비교할 수 없는

강력하고 편리한 로깅 기능을 사용할 수 있다.

 

 

기본적인 log4j.properties

아래 로그설정은 로깅 메시지를 화면에도 출력하고 파일로도 출력한다.

파일의 경우에는 매일매일 날짜별로 다른 파일을 사용하므로

한개의 로그 파일이 무한정 커지는 것을 걱정할 필요는 없다.

이 설정대로 하면 로깅 메시지에 로그를 남긴 소스파일의 이름과

소스에서 메소드 이름과 줄 번호까지 출력된다.

System.out.println()으로는 꿈도 못꾸는 기능들이다.


log4j.rootLogger = DEBUG, stdout, dailyfile
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p (%F[%M]:%L) [%d] - %m%n
log4j.appender.dailyfile.Threshold = DEBUG
log4j.appender.dailyfile = org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyfile.File = logfile.log
log4j.appender.dailyfile.layout = org.apache.log4j.PatternLayout
log4j.appender.dailyfile.layout.ConversionPattern=%5p (%F[%M]:%L) [%d] - %m%n


저기서 logfile.log 가 로그의 내용을 출력할 파일 이름이다.
적당히 다른 이름으로 바꾼다. 절대경로로 줘도되고 위와 같이 상대경로로 줘도 된다.
위 파일을 클래스패스가 걸린 디렉토리에 두면 된다.
웹 어플리케이션은 WEB-INF/classes에 두면 된다.
로그는 어떻게 남기지?
각 클래스에서 로그를 남길 때는 다음과 같이...


// 로거 임포트하기
import! org.apache.log4j.Logger;

public class ClassName {
    /** Log4J 로거 얻기 */
    private Logger log = Logger.getLogger(ClassName.class);

    public void method() {

        if (log.isDebugEnabled()) {
            log.debug("디버깅용 메시지");
        }
        log.info("정보를 남기기위한 메시지");
        
        try {
            // 어쩌구 저쩌구 실행...
        } catch (Exception ex) {
            // 로그에 예외 메시지도 함께 남기기
            log.error("예외가 발생했어요~~", ex);
        }
    }
}


ClassName.class는 로거가 출력할 클래스의 이름이다.
그냥 항상 (클래스이름.class)로 하면 된다.

만약 static 메소드에서 로거를 사용해야 한다면 로거를 생성하는 부분을


private static Logger log = Logger.getLogger(ClassName.class);

 

위와 같이 static 으로 선언하면 된다.

실제로 로그 메시지 출력이 어떻게 되는지는 직접 확인해보면 알 수 있을 것이다.

마무리~
자, 이제 프로그램에서 보기 싫은 System.out.println()을 몽땅 없애버리자!!
Log4J하 나만으로도 디버깅하기 쉽고 뽀대나고 어딘가 비싸보이는 프로그램이 된다. ^^; 
by 권남
 
출처 :  http://kwon37xi.egloos.com/2176487

 

==================================================================================================

 


Log4j를 이용하여 로그를 기록하자!

오픈 소스 프로젝트인 Log4j를 이용하여 자바 어플리케이션에서

빠르고 효과적인 로그 서비스를 구축할 수 있다.
 

요약
오픈 소스 프로젝트인 Log4j는 카테고리, 어펜더, 레이아웃을 통해

개발자들이 매우 손쉽게 다양한 형태의 로깅을 할 수 있도록 해준다.

또, Log4j는 설정 파일을 이용함으로써 소스 코드를 재컴파일 할 필요 없이

런타임에 로그 정보를 변경할 수 있도록 해 주며,

NDC(nested Diagnostic contexts)를 이용하여

좀더 분석이 용이한 로그를 남길 수 있도록 해 준다.

프로바이더: 최범균 
--------------------------------------------------------------------------------
내 용구성 
Log4j 
Log4j의 설정 
NDC(Nested Diagnostic Contexts) 
결론 
[프 린트형식으로보기] 
--------------------------------------------------------------------------------
Log4j


오늘날 프로젝트에서 많이 사용되는 웹서버, 어플리케이션 서버,

DBMS를 비롯한 대부분의 상업용 어플리케이션은

그 어플리케이션에서 발생하는 사건들을 기록하기 위해 로그를 남기고 있다.

특히, 경험 많은 개발자들은 로깅은 어플리케이션 개발 및 유지보수에 있어 중요한 요소임을 지적한다.

실제로 로그 기록을 남김으로써 몇가지 장점을 얻을 수 있다.

무엇보다도 로그는 어플리케이션이 실행되는 동안의 정확한 상황과 상태 정보를 제공한다.

둘째로, 로그 출력을 파일이나 DB와 같은 곳에 기록하여 나중에 로그 결과를 분석할 수 있다.

마지막으로, 개발 기간 중에 로그 패키지를 문제 검사 툴로 사용할 수도 있다.

 

카테고리, 어펜더 그리고 레이아웃
Log4j는 세 개의 주요 컴포넌트를 갖고 있다.

카테고리(Category) 
어펜더(Appender) 
레이아웃(Layouts) 
개발자는 메시지 타입과 우선순위에 따라 메시지를 기록하고

런타임에 이 메시지들의 포맷을 어떻게 작성하고

어디에 출력할지를 제어할 수 있도록 하기 위해 이 세개의 컴포넌트를 함께 사용한다.

이 세 가지 컴포넌트에 대해 차례대로 알아보도록 하자.

 

카테고리 계층(Category hierarchy)
몇몇 로깅 API의 가장 좋은 장점은 특정한 기준에 따라

로그를 기록할지의 여부를 결정할 수 있다는 점이다.

이것은 로그에 기록될 모든 문장들이

로깅 API 개발자가 정해 놓은 기준에 따라 분류된다는 것을 의미한다.

Log4j 역시 org.apache.log4j.Category 클래스를 통해서 이러한 분류 기준을 제시하고 있다.

Category 클래스는 org.apache.log4j 패키지의 핵심 클래스이며, 카테고리를 나타낸다.

카테고리는 이름을 가진 개체이다.

카테고리의 이름은 자바의 패키지 이름과 비슷한 구조를 갖는다.

즉, 카테고리 이름은 com.javacan과 같은 형태를 가진다.

이 이름에 따라 카테고리는 부모 카테고리와 자식 카테고리로 구분된다.

예를 들어, com.javacan의 부모 카테고리의 이름은 com 이며,

이름이 com.javacan.article인 카테고리는 com.javacan의 자식 카테고리가 되는 것이다.

따라서, 카테고리 사이에는 계층이 형성된다.

계층의 가장 상위에 있는 카테고리를 루트 카테고리라고 하며,

루트 카테고리는 다음과 같은 특징을 갖고 있다.

 

1. 루트 카테고리는 항상 존재한다. 
2. 이름을 사용하여 루트 카테고리를 읽어올 수 없다.
3. Category 클래스의 static 메소드인 getRoot() 메소드를 사용하여 루트 카테고리를 구할 수 있다.

static 메소드인 getInstance() 메소드는 모든 다른 카테고리의 인스턴스를 생성한다.

getInstnace() 메소드는 원하는 카테고리의 이름을 파라미터로 입력받는다.

Category 클래스의 몇몇 기본 메소드는 다음과 같다.

package org.apache.log4j;

public class Category {

   // Creation & retrieval! methods:
   public static Category getRoot();
   public static Category getInstance(String name);

   // printing methods:
   public void debug(String message);
   public void info(String message);
   public void warn(String message);
   public void error(String message);

   // generic printing method:
   public void log(Priority p, String message);

   .......
}


카테고리마다 org.apache.log4j.Priority 클래스에 정의된 값을 사용하여 우선순위를 지정할 수 있다.

현재 Priority 클래스에는 FATAL, ERROR, WARN, INFO, DEBUG의

5개의 우선순위가 정의되어 있다.

나열한 순서대로 우선 순위가 낮아진다.

겉으로 보기에 제한된 집합을 갖도록 한 이유는 정적인 우선순위 집합보다

더욱 더 유연한 카테고리 계층을 만들 수 있도록 하기 위해서이다.

하지만, Priority 클래스를 상속받아서 자신만의 우선순위를 정의할 수도 있다.

만약 주어진 카테고리가 할당된 우선순위를 갖고 있지 않다면,

카테고리 계층도에서 할당된 우선순위를 갖고 있는 가장 가까운 상위 카테고리로부터 우선순위를 상속받는다.

따라서 루트 카테고리가 할당된 우선순위를 갖고 있을 경우

결과적으로 모든 카테고리가 그 우선순위를 상속받게 된다.

로깅 요청은 카테고리 인스턴스의 출력 메소드 중 하나를 호출하면 된다.

출력 메소드는 다음과 같다.

error()
warn()
info()
debug()
log()
출력 메소드는 로깅 요청의 우선순위를 결정한다.

예를 들어, cat가 카테고리 인스턴라고 할 경우,

cat.info("....")는 INFO 우선순위로 로깅을 요청한다.

만약 현재 요청한 로깅의 우선순위가 카테고리의 우선순위와 같거나 높으면

그 로깅 요청이 가능하다고 말한다.

그렇지 않을 경우 그 요청은 불가능하다고 한다.

다음은 로깅 요청의 가능/불가능 여부가 어떻게 처리되는 지를 보여주는 예이다.

// 이름이 "com.foo"인 카테고리 인스턴스를 구한다.
Category cat = Category.getInstance("com.foo");

// 카테고리의 우선순위를 설정한다.
cat.setPriority(Priority.INFO);

// WARN >= INFO 이기 때문에, 이 요청은 가능하다.
cat.warn("Low fuel level.");

// DEBUG < INFO 이기 때문에, 이 요청은 불가능하다.
cat.debug("Starting search for nearest gas station.");

// 이름이 "com.foo.Bar"인 카테고리의 인스턴스를 생성한다.
// 이 카테고리는 이름이 "com.foo"인 카테고리를 상속 받는다.
// 따라서 이 카테고리 인스턴스는 INFO 우선순위를 갖는다.
Category barcat = Category.getInstance("com.foo.Bar");

// INFO >= INFO 이므로, 이 요청은 가능하다.
barcat.info("Located nearest gas station.");

// DEBUG < INFO 이므로, 이 요청은 불가능하다.
barcat.debug("Exiting gas station search");


같은 이름을 사용하여 getInstance() 메소드를 호출하면

항상 같은 카테고리 오브젝트에 대한 레퍼런스를 리턴한다.

따라서, 일단 특정한 이름을 갖는 카테고리 인스턴스를 설정하면,

그 인스턴스의 레퍼런스를 전달할 필요 없이

프로그램내의 어떤 곳에서든지 그 카테고리의 인스턴스를 읽어올 수 있으며,

특정한 순서없이 카테고리를 생성 및 설정할 수 있다.

또한, 자식 카테고리를 생성한 이후에 부모 카테코리를 찾고 연결할 수 있다.

Log4j 환경은 일반적으로 어플리케이션을 초기화할 때 설정하는데,

설정 파일을 읽어오는 시점에서 설정하는 경우가 많다.

Log4j에서 카테고리의 이름은 그 카테고리의 인스턴스를 생성할 때 사용한

클래스의 완전한 이름과 동일하게 짓는 것이 카테고리를 정의하는 직관적인 방법이다.

로그에는 카테고리를 생성할 때 사용한 이름이 기록되기 때문에,

카테고리의 이름이 클래스의 이름과 일치하도록 하는 방법은

로그 메시지의 출처를 구분하는 데에도 도움을 준다.

이러한 방법이 일반적이지만, 이외에도 다양한 방법을 사용하여 카테고리의 이름을 지을 수 있다.

Log4j는 가능한 카테고리의 집합을 제한하고 있지 않으며,

개발자는 카테고리의 이름을 원하는 대로 지을 수 있다.

 

어펜더와 레이아웃
Log4j는 카테고리에 기반하여 로깅 요청의 가능/불가능 여부를 결정하는 기능 뿐만 아니라,

로깅 요청을 다중의 어펜더(appender)에 출력할 수 있다.

여기서 어펜더는 출력의 목적지를 나타낸다.

현재 콘솔, 파일, GUI 컴포넌트, 원격 소켓 서버, NT 이벤트 로거

그리고 원격 유닉스 시스로그 데몬으로 연결되는 어펜더가 존재한다.

카테고리는 다중의 어펜더를 참조할 수 있다.

카테고리에 들어온 각각의 가능한 로깅 요청은

그 카테고리에 있는 모든 어펜더에 전달되며,

뿐만 아니라 카테고리 계층의 상위에 있는 어펜더에도 전달된다.

즉, 어펜더는 카테고리 계층으로부터 상속된다.

예를 들어, 루트 카테고리에 콘솔 어펜더를 추가했다면,

모든 가능한 로깅 요청은 적어도 콘솔에 로그 메시지를 출력할 것이다.

만약 C라고 불리는 카테고리에 파일 어펜더를 추가했다면,

C와 C의 자식 카테고리에 대한 가능한 로깅 요청은 콘솔과 파일에 메시지를 출력할 것이다.

또한 출력 목적지 뿐만 아니라 출력 형식도 변경할 수 있다.

각각의 어펜더는 그 어펜더에 출력될 메시지의 형식을 가지고 있으며,

이는 그 어펜더와 특정 레이아웃(layout)을 관련시킴으로써 가능해진다.

레이아웃은 사용자가 지정한 값에 따라 로깅 요청의 포맷을 결정하고,

어펜더는 레이아웃을 통해 포맷된 로그 내용를 그것의 목적지에 출력한다.

Log4j의 표준 배포판에 있는 PatternLayout은

사용자가 C 언어의 printf() 함수와 비슷한 변환 패턴에 따라 출력 포맷을 지정할 수 있도록 해준다.

예를 들어, 변환 패턴이 %r [%t]% -5p %c - %m%n 인 PatternLayout은

다음과 비슷한 결과를 출력한다.

176 [main] INFO org.foo.Bar - Located nearest gas station.


위의 출력 결과는 다음과 같다.

첫번째 필드는 프로그램이 시작한 이후 경과한 시간(1/1000초 단위)을 나타낸다. 
두번째 필드는 로그 요청을 한 쓰레드를 나타낸다. 
세번째 필드는 로그의 우선순위를 나타낸다. 
네번째 필드는 로그 요청과 관련된 카테고리의 이름을 나타낸다. 
나머지는 로그에 기록할 메시지이다.

[다음]


--------------------------------------------------------------------------------
프 로바이더 mailto: madvirus@madvirus.net:
현 재 티페이지 글로벌(주)의 기술연구소에 있으며,

'JSP 웹 어플리케이션 개발(가메출판사)'을 이동훈씨와 함께 저술한 바 있다. 
--------------------------------------------------------------------------------
관 련자료 
예제 소스 코드 
관련링크 
Log4j 프로젝트 홈페이지 
http://jakarta.apache.org/log4j/index.html 
Sun 의 로깅 API 규약 
http://java.sun.com/aboutJava/communityprocess/jsr/jsr_047_log.html


--------------------------------------------------------------------------------



출처: http://globalhost.interdol.com/355 [[인터돌™] 프로그램 공부 해보자!! 열심히~~~]

반응형
728x90

[JAVA] 정규표현식, Matcher 메서드 사용방법과 그룹 개념이해



Matcher 클래스 메서드들

find() : 패턴이 일치하는 경우 true를 반환하고, 그 위치로 이동(여러개가 매칭되는 경우 반복 실행가능)
find(int start) : start위치 이후부터 매칭검색을 수행
start() : 매칭되는 문자열 시작위치 반환
start(int group) : 지정된 그룹이 매칭되는 시작위치 반환
end() : 매칭되는  문자열 끝 다음 문자위치 반환
end(int group) : 지정되 그룹이 매칭되는 끝 다음 문자위치 반환

group() : 매칭된 부분을 반환
group(int group) : 매칭된 부분중 group번 그룹핑 매칭부분 반환
groupCount() : 패턴내 그룹핑한(괄호지정) 전체 갯수 반환
matches() : 패턴이 전체 문자열과 일치할 경우 true 반환


그룹화 이해하기

패턴 내에서 그룹을 지정하기 위해서 ()를 통해 그룹을 설정해주면 되고, () 갯수만큼 그룹이 만들어 진다.


위 예제에서는 2개의 그룹이 설정이 되었으며, 각 그룹은 group()메서드를 통해 1,2번으로 접근이 가능하다.
group()나 group(0) 메서드는 매칭된 전체 문자열을 반환한다.



매칭 위치 반환

start()메서드를 통해 패턴이 일치하는 문자열의 시작 위치와 end() 메서드를 통해 패턴이 끝나는 문자열의 다음 문자위치를 반환한다.


end() 메서드가 패턴이 일치하는 문자열의 끝부분 위치가 아닌 끝부분 다음 문자의 위치라는 것을 확인하자.

start(int group)와 end(int group)에 group이 지정되는 경우 해당 그룹이 매칭되는 위치를 반환하게 된다.

이보다 더 많은 메서드들이 있지만 이정도만 알아도 기본적인 패턴 매칭하는데는 문제가 없어 보인다^^

반응형
728x90

보안사고가 잦은 요즘 고객사에서 파일로 남기는 로그가 있었는데

모든 액션에 대해서 6하원칙 원인 분석이 가능하도록 DB에 남겨달라는 요청이 있다.

 

확인을 해보니 log4j 에서 파일만 지원하는 줄 알았는데 콘솔, DB 에 저장 가능하다고 한다.

 

JDBCAppender 를 검색해보면 여러가지 나오는데 

MDC까지 활용을 하면 log4j에서 지원하는 기본기능에 더해서 내가 원하는 변수들도 저장이 가능하다.

 

MDC는 hashtable 타입같은거고 NDC는 stack 형식이며

NDC는 메모리 부하가 있다고 하니 꼭 remove를 해야 한다.

웬만하면 MDC 쓰는 편이 명확하고 좋은 것 같음. (org.apache.log4j.MDC)

 

 

1. 스프링의 인터셉터를 생성 혹은 추가 

    <bean id="beanNameUrlMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
        <property name="interceptors">
         <list>
             <ref bean="LogInterceptor"/>
            </list>
        </property>
        <property name="order"><value>1</value></property>
    </bean> 

2. LogInterceptor 라는 bean 설정 

<bean id="LogInterceptor" class="원하는 패키지 경로.LogInterceptor" />

 

3. LogInterceptor 클래스에서 HandlerInterceptorAdapter 를 extends 받아서 구현 

아래 내용은 preHandle 메소드안에서 구현한다.

 

     String url = request.getServletPath();
     String ip = request.getRemoteAddr();

 

     Enumeration param = request.getParameterNames();
     while(param.hasMoreElements())
     {
      String name = (String)param.nextElement();
      String value = request.getParameter(name);
      if(null != value && !"".equals(value))
      {
       params += ("["+name+":"+value+"]");
      }
     }
     
     MDC.put("ACCOUNT_ID", accountId);
     MDC.put("ACCOUNT_IP", ip);
     MDC.put("PAGE_URL", url);
     MDC.put("PARAMS", params);
     
     return true;

 

 

4. log4j.properties 에서 아래 내용 추가 (아래내용은 파일과 DB를 동시에 남기는 설정)

 

 

#================================================================================
# ibatis shkim.add.IBATIS_DB_LOG
#================================================================================
log4j.logger.com.ibatis=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.java.sql.Connection=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.java.sql.Statement=DEBUG, IBATIS_LOG
log4j.logger.java.sql.PreparedStatement=DEBUG, IBATIS_LOG
#log4j.logger.java.sql.ResultSet=DEBUG, IBATIS_LOG
log4j.logger.spectra.base.sql.ibatis=DEBUG, IBATIS_LOG, IBATIS_DB_LOG

log4j.appender.IBATIS_LOG=org.apache.log4j.DailyRollingFileAppender
log4j.appender.IBATIS_LOG.Threshold=DEBUG
log4j.appender.IBATIS_LOG.File=원하는파일저장경로/ibatis.log
log4j.appender.IBATIS_LOG.DatePattern='.'yyyy-MM-dd
log4j.appender.IBATIS_LOG.layout=org.apache.log4j.PatternLayout
log4j.appender.IBATIS_LOG.layout.ConversionPattern=%d{MM-dd HH:mm:ss} %-10t %-10x %-5p %-24.24C{2} %-30.30M %m%n
log4j.appender.IBATIS_LOG.ImmediateFlush=True

 

#DB LOG SETTING s
log4j.appender.IBATIS_DB_LOG=org.apache.log4j.jdbcplus.JDBCAppender
log4j.appender.IBATIS_DB_LOG.url=jdbc:oracle:thin:@디비아이피혹은호스트:1521:orcl
log4j.appender.IBATIS_DB_LOG.dbclass=oracle.jdbc.driver.OracleDriver
log4j.appender.IBATIS_DB_LOG.username=디비접속계정
log4j.appender.IBATIS_DB_LOG.password=디비접속비밀번호
log4j.appender.IBATIS_DB_LOG.sql=INSERT INTO T_ACCOUNT_ACTION_LOG( LOG_DATE,ACCOUNT_ID,ACCOUNT_IP,PAGE_URL,QUERY_NAME,PARAMS  ) values (to_char(SYSDATE, 'YYYYMMDDhh24miss'),'@MDC:ACCOUNT_ID@','@MDC:ACCOUNT_IP@','@MDC:PAGE_URL@','@MSG@','@MDC:PARAMS@')
log4j.appender.IBATIS_DB_LOG.layout=org.apache.log4j.PatternLayout
log4j.appender.IBATIS_DB_LOG.layout.ConversionPattern=%m%n
log4j.appender.IBATIS_DB_LOG.buffer=1
log4j.appender.IBATIS_DB_LOG.commit=true
log4j.appender.IBATIS_DB_LOG.quoteReplace=true
log4j.appender.IBATIS_DB_LOG.throwableMaxChars=3000
#DB LOG SETTING e 

 

5. 테이블 생성 쿼리

--------------------------------------------------------------------------------
-- 상담사 로그 저장 테이블 생성 스크립트
-- 작성자 : shkim,
-- 작성일 : 2014.01.23
--------------------------------------------------------------------------------
-- Table 테이블명

CREATE TABLE 테이블명
(
  LOG_DATE    CHAR(14)  DEFAULT to_char(sysdate, 'YYYYMMDDhh24miss'), 
  ACCOUNT_ID  VARCHAR2(128 BYTE) ,
  ACCOUNT_IP  VARCHAR2(128 BYTE) ,
  PAGE_URL    VARCHAR2(128 BYTE) ,
  QUERY_NAME  VARCHAR2(500 BYTE) ,
  PARAMS      VARCHAR2(4000 BYTE) 
);

CREATE INDEX IDX_LOG_DATE_ID_ASC ON 테이블명(LOG_DATE, ACCOUNT_ID);
CREATE INDEX IDX_LOG_DATE_ID_DESC ON 테이블명(LOG_DATE DESC, ACCOUNT_ID);

COMMENT ON TABLE 테이블명 IS 'enomix사용자액션저장테이블';
COMMENT ON COLUMN 테이블명.LOG_DATE IS '액션시간';
COMMENT ON COLUMN 테이블명.ACCOUNT_ID IS '사용자ID null일 경우 시스템호출 혹은 로그인 전 발생한 액션';
COMMENT ON COLUMN 테이블명.ACCOUNT_IP IS '사용자IP null일 경우 시스템호출';
COMMENT ON COLUMN 테이블명.PAGE_URL IS '호출URL null일 경우 시스템호출';
COMMENT ON COLUMN 테이블명.QUERY_NAME IS '호출쿼리명';
COMMENT ON COLUMN 테이블명.PARAMS IS '파라미터로 검색조건이나 검색기간 기타 request 정보등이 담겨있다'; 

 

 

 

 출처 : http://m.blog.naver.com/0131v/110183988915

반응형
728x90

이미지 태그 src 값 추출

아래의 html 파일에서 img 태그의 src 값만 추출해보겠습니다.

유지보수나 개발을 하다보시면 게시글의 본문에 html 소스가 통으로 들어가 있는 경우를 많이 보게 되므로 그것을 예로 하였습니다.


img.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>img html</h1>
<img src="img/Chrysanthemum.jpg"/>
<img src="img/Desert.jpg"/>
<img src="img/Hydrangeas.jpg"/>
</body>
</html>


정규표현식을 이용하여 src 값을 추출하는데,

여기서 자바 1.4 이상부터 제공하는 util.regex 패키지의 Pattern , Matcher 클래스를 사용합니다.

사용하는 메서드


Patter Class

static Pattern compile(String regex) : 주어진 정규표현식으로부터 패턴을 만들어냅니다.

static Matcher matcher (CharSequence input) : 전달된 텍스트에서 패턴을 찾는 Matcher 객체를 만든다.

Matcher Class

find() : 패턴이 일치하는 경우 true를 반환하고, 그 위치로 이동합니다. (여러개가 매칭되는 경우 반복 실행가능함)

group() : 매칭된 부분을 반환

group(int group) : 매칭된 부분중 group번 매칭 부분을 반환


ImgExtract.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class ImgExtract {
    public static void main(String[] args){
        String text = "<!DOCTYPE html><head><meta charset='UTF-8'><title>Insert title here</title></head><h1>img html</h1><img src='img/Chrysanthemum.jpg'/><img src='img/Desert.jpg'/><img src='img/Hydrangeas.jpg'/>";
        Pattern pattern = Pattern.compile("<img[^>]*src=[\"']?([^>\"']+)[\"']?[^>]*>"); //img 태그 src 추출 정규표현식
        Matcher matcher = pattern.matcher(text);
         
        while(matcher.find()){
            System.out.println(matcher.group(1));
        }
    }
}

text 변수에는 위의 html 코드를 String 형태로 쭉 넣었습니다.

img src 추출 정규 표현식 : <img[^>]*src=[\"']?([^>\"']+)[\"']?[^>]*>

간략하게 설명하자면

String 형태의 정규표현식을 이용하여 패턴(Pattern 객체)을 만들어냅니다.

만들어진 패턴에 추출 대상이 될 텍스트를 집어넣고, matcher 메서드는 매칭결과를 Matcher 객체로 반환합니다.

find() 메서드를 통해 해당 위치로 이동하고

matcher.group(1) 메서드를 통해 1번째 group의 매칭부분을 반환합니다.

group() 메서드를 매칭된 내용 전체가 반환되므로 img 태그 전체가 반환됩니다.

그리하여 group(1) 메서드를 사용하여 첫번째 그룹의 값을 추출해내어야 하는데

여기서 첫번째 그룹이란 해당 정규식에서 괄호로 묶인

 <img[^>]*src=[\"']?([^>\"']+)[\"']?[^>]*> 부분을 의미합니다. (굵게 표시된 부분)

(저도 정규표현식을 몰라 자세히 설명드리지 못해 죄송합니다.)


실행결과입니다.


가끔식 img 태그가 아닌 IMG 태그의 형태로 저장되어 있는 경우가 있습니다.

이럴경우 대소문자 구분을 없애주는 정규표현식을 전체 정규표현식 앞에 입력해주시면 됩니다.

(?i) 정규표현식입니다.

위의 img src 정규표현식에 추가하면

(?i)<img[^>]*src=[\"']?([^>\"']+)[\"']?[^>]*>

의 형태가 됩니다.


이상 포스팅을 마치겠습니다.

감사합니다.



출처: http://joont.tistory.com/56 [Toward the Developer]

반응형

+ Recent posts