• (一)敏感信息混淆


    最近网上出现的安全事故很多,最惨的莫过于那场酒店事件,因此项目整改也需要对用户的敏感信息进行脱敏,由于前期的项目并没有规划这一模块,为了满足安全规范达到上线标准,需要对项目进行改造。


    改造方案

      1. 不能采用手动encode/decode的方式(避免在某个地方忘记encode/decode了)

      2. 非侵入性改造,后续的coding的时候无需在费心思考虑

    方案1: 从数据层入手,在提交数据库前对敏感字段进行encode,在取得数据集后对结果集的敏感字段进行decode

      项目中选择mybatis为中间件,因此可以使用mybatis拦截器,方案实现起来简单,符合条件2,但却会带来关键问题:在单业务编写时基本没有问题,但是在多业务关联的时候却会对关联的字段有影响,需要在手动encode,不符合条件1,因此方案被pass。

    方案2: 从控制层入手,在接收客户端提交的数据时对敏感字段进行encode,在response序列化对象时对敏感字段进行decode。

      该方案能保证敏感字段在业务逻辑实现过程中都是混淆的,后续也无需关注哪个对象的哪个字段是需要encode/decode,满足改造方案。


     实现方案

       1. 定义敏感字段类型,由于混淆后的字段类型均可以为字符串,因此我们可以仿造String类型来进行定义(由于String类是final,因此不考虑继承的方式)

    /**
     * @author zhangqiuyang
     * Created on 2018/8/17.
     */
    public class SecretString implements java.io.Serializable, Comparable<String>, CharSequence {
        @Setter
        @Getter
        private String value;
    
        public SecretString(String value) {
            this.value = value;
        }
    
        /**
         * Returns the length of this character sequence.  The length is the number
         * of 16-bit <code>char</code>s in the sequence.
         *
         * @return the number of <code>char</code>s in this sequence
         */
        @Override
        public int length() {
            return value.length();
        }
    
        /**
         * Returns a string representation of the object. In general, the
         * {@code toString} method returns a string that
         * "textually represents" this object. The result should
         * be a concise but informative representation that is easy for a
         * person to read.
         * It is recommended that all subclasses override this method.
         * <p>
         * The {@code toString} method for class {@code Object}
         * returns a string consisting of the name of the class of which the
         * object is an instance, the at-sign character `{@code @}', and
         * the unsigned hexadecimal representation of the hash code of the
         * object. In other words, this method returns a string equal to the
         * value of:
         * <blockquote>
         * <pre>
         * getClass().getName() + '@' + Integer.toHexString(hashCode())
         * </pre></blockquote>
         *
         * @return a string representation of the object.
         */
        @Override
        public String toString() {
            return value;
        }
    
        /**
         * Returns the <code>char</code> value at the specified index.  An index ranges from zero
         * to <tt>length() - 1</tt>.  The first <code>char</code> value of the sequence is at
         * index zero, the next at index one, and so on, as for array
         * indexing.
         *
         * <p>If the <code>char</code> value specified by the index is a
         * <a href="{@docRoot}/java/lang/Character.html#unicode">surrogate</a>, the surrogate
         * value is returned.
         *
         * @param index the index of the <code>char</code> value to be returned
         * @return the specified <code>char</code> value
         * @throws IndexOutOfBoundsException if the <tt>index</tt> argument is negative or not less than
         *                                   <tt>length()</tt>
         */
        @Override
        public char charAt(int index) {
            return value.charAt(index);
        }
    
        /**
         * Returns a <code>CharSequence</code> that is a subsequence of this sequence.
         * The subsequence starts with the <code>char</code> value at the specified index and
         * ends with the <code>char</code> value at index <tt>end - 1</tt>.  The length
         * (in <code>char</code>s) of the
         * returned sequence is <tt>end - start</tt>, so if <tt>start == end</tt>
         * then an empty sequence is returned.
         *
         * @param start the start index, inclusive
         * @param end   the end index, exclusive
         * @return the specified subsequence
         * @throws IndexOutOfBoundsException if <tt>start</tt> or <tt>end</tt> are negative,
         *                                   if <tt>end</tt> is greater than <tt>length()</tt>,
         *                                   or if <tt>start</tt> is greater than <tt>end</tt>
         */
        @Override
        public CharSequence subSequence(int start, int end) {
            return value.subSequence(start, end);
        }
    
    
        /**
         * Compares this object with the specified object for order.  Returns a
         * negative integer, zero, or a positive integer as this object is less
         * than, equal to, or greater than the specified object.
         *
         * <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
         * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
         * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
         * <tt>y.compareTo(x)</tt> throws an exception.)
         *
         * <p>The implementor must also ensure that the relation is transitive:
         * <tt>(x.compareTo(y)&gt;0 &amp;&amp; y.compareTo(z)&gt;0)</tt> implies
         * <tt>x.compareTo(z)&gt;0</tt>.
         *
         * <p>Finally, the implementor must ensure that <tt>x.compareTo(y)==0</tt>
         * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
         * all <tt>z</tt>.
         *
         * <p>It is strongly recommended, but <i>not</i> strictly required that
         * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>.  Generally speaking, any
         * class that implements the <tt>Comparable</tt> interface and violates
         * this condition should clearly indicate this fact.  The recommended
         * language is "Note: this class has a natural ordering that is
         * inconsistent with equals."
         *
         * <p>In the foregoing description, the notation
         * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
         * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
         * <tt>0</tt>, or <tt>1</tt> according to whether the value of
         * <i>expression</i> is negative, zero or positive.
         *
         * @param o the object to be compared.
         * @return a negative integer, zero, or a positive integer as this object
         * is less than, equal to, or greater than the specified object.
         * @throws NullPointerException if the specified object is null
         * @throws ClassCastException   if the specified object's type prevents it
         *                              from being compared to this object.
         */
        @Override
        public int compareTo(String o) {
            return value.compareTo(o);
        }
    
        /**
         * 解密后的值
         *
         * @return
         */
        public String decryptValue() {
            return SecurityUtil.decryptString(value);
        }
    }

       2. 定义敏感字段类型的序列化器

    /**
     * @author zhangqiuyang
     * Created on 2018/8/17.
     */
    @JsonComponent
    public class SecretStringJsonCombinedSerializer {
    
    
        /**
         * 密文序列化
         */
        public static class SecretStringJsonSerializer extends JsonSerializer<SecretString> {
            /**
             * 重写序列化SecretString类型字段
             *
             * @param secretString
             * @param jsonGenerator
             * @param serializerProvider
             * @throws IOException
             */
            @Override
            public void serialize(SecretString secretString, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                    throws IOException {
    
                jsonGenerator.writeString(secretString.decryptValue());
            }
        }
    
        /**
         * 密文反序列化
         */
        public static class SecretStringJsonDeserializer extends JsonDeserializer<SecretString> {
    
            @Override
            public SecretString deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
                    throws IOException {
                TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
                return new SecretString(SecurityUtil.encryptString(((TextNode) treeNode).asText()));
            }
        }
    
    
    }

    综上,改造基本完成。

    github:https://github.com/zqyx5201/SecretStringTest

    作者: zhangQ
    个人主页:https://www.yxzqy.com/
    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    7-25 念数字
    7-24 约分最简分式
    7-23 币值转换
    HDU-1102-Constructing Roads
    HDU-1301-Jungle Roads
    链式向前星
    HDU-1217-Arbitrage(SPFA)
    POJ-1258-Agri-Net
    HDU-1863-畅通工程
    POJ-3050-Hoscotch
  • 原文地址:https://www.cnblogs.com/zqyx/p/9635562.html
Copyright © 2020-2023  润新知